📄 pkcs15_set.c
字号:
/****************************************************************************
* *
* cryptlib PKCS #15 Set-item Routines *
* Copyright Peter Gutmann 1996-2007 *
* *
****************************************************************************/
#if defined( INC_ALL )
#include "crypt.h"
#include "keyset.h"
#include "pkcs15.h"
#else
#include "crypt.h"
#include "keyset/keyset.h"
#include "keyset/pkcs15.h"
#endif /* Compiler-specific includes */
#ifdef USE_PKCS15
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Check whether we can add anything to a PKCS #15 personality */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 8, 9 ) ) \
static int checkAddInfo( const PKCS15_INFO *pkcs15infoPtr,
IN_HANDLE const CRYPT_HANDLE iCryptHandle,
const BOOLEAN isCertChain,
const BOOLEAN privkeyPresent,
const BOOLEAN certPresent,
const BOOLEAN pkcs15keyPresent,
const BOOLEAN pkcs15certPresent,
OUT BOOLEAN *isCertUpdate,
INOUT ERROR_INFO *errorInfo )
{
MESSAGE_DATA msgData;
BOOLEAN unneededCert, unneededKey;
int status;
assert( isReadPtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
assert( isWritePtr( isCertUpdate, sizeof( BOOLEAN ) ) );
REQUIRES( isHandleRangeValid( iCryptHandle ) );
REQUIRES( errorInfo != NULL );
/* Clear return value */
*isCertUpdate = FALSE;
/* Check what we can update (if anything) */
unneededKey = privkeyPresent & pkcs15keyPresent;
unneededCert = certPresent & pkcs15certPresent;
if( ( ( unneededCert && !privkeyPresent ) || \
( unneededKey && unneededCert ) ) && \
pkcs15infoPtr->validTo > MIN_TIME_VALUE )
{
time_t validTo;
/* The certificate would be a duplicate, see if it's more recent
than the existing one. We only perform this check if there's a
validTo time stored for the certificate since without this
restriction any certificate without a stored time could be
overwritten */
setMessageData( &msgData, &validTo, sizeof( time_t ) );
status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_VALIDTO );
if( cryptStatusOK( status ) && validTo > pkcs15infoPtr->validTo )
{
time_t validFrom;
/* It's a newer certificate, don't treat it as a duplicate.
This check is effectively impossible to perform automatically
since there are an infinite number of variations that have to
be taken into account, for example a certificate for the same
key issued by a different CA, same CA but it's changed the
bits it sets in the keyUsage (digitalSignature vs.
nonRepudiation), slightly different issuer DN (Thawte
certificates with a date encoded in the DN), and so on and so
on. Because this really requires manual processing by a
human we don't even try and sort it all out but just allow a
certificate for a given key (checked by the ID match) to be
replaced by a newer certificate for the same key. This is
restrictive enough to prevent most obviously-wrong
replacements while being permissive enough to allow most
probably-OK replacements */
unneededCert = FALSE;
*isCertUpdate = TRUE;
/* There's one special-case situation in which odd things can
happen when updating certificates and that's when adding a
future-dated certificate, which would result in the
certificate being replaced with one that can't be used yet.
There's no clean way to handle this because in order to know
what to do we'd have to be able to guess the intent of the
user, however for anything but signature certificates it's
likely that the hit-and-miss certificate checking performed
by most software won't even notice a future-dated
certificate, and for signature certificates the semantics of
signing data now using a certificate that isn't valid yet are
somewhat uncertain. Since in most cases no-one will even
notice the problem, we throw an exception in the debug build
but don't do anything in release builds. This is probably
less annoying to users than having the code reject an
otherwise-valid future-dated certificate. If anyone ever
complains about this then we can ask the users at that time
what sort of behaviour they're prefer */
setMessageData( &msgData, &validFrom, sizeof( time_t ) );
status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_VALIDFROM );
if( cryptStatusOK( status ) && \
validFrom > getApproxTime() + 86400L )
{
assert( !"Attempt to replace certificate with future-dated certificate" );
}
}
}
/* Make sure that we can update at least one of the objects in the PKCS
#15 personality */
if( ( unneededKey && !certPresent ) || /* Key only, duplicate */
( unneededCert && !privkeyPresent ) || /* Certificate only, duplicate */
( unneededKey && unneededCert ) ) /* Key+certificate, duplicate */
{
/* If it's anything other than a certificate chain, we can't add
anything */
if( !isCertChain )
{
retExt( CRYPT_ERROR_DUPLICATE,
( CRYPT_ERROR_DUPLICATE, errorInfo,
"No new data to add" ) );
}
/* Tell the caller that it's an opportunistic certificate-chain
update */
return( OK_SPECIAL );
}
return( CRYPT_OK );
}
/****************************************************************************
* *
* Add a Key *
* *
****************************************************************************/
/* Add an item to the PKCS #15 keyset */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int setItemFunction( INOUT KEYSET_INFO *keysetInfoPtr,
IN_HANDLE const CRYPT_HANDLE cryptHandle,
IN_ENUM( KEYMGMT_ITEM ) \
const KEYMGMT_ITEM_TYPE itemType,
IN_BUFFER_OPT( passwordLength ) const char *password,
IN_LENGTH_NAME_Z const int passwordLength,
IN_FLAGS( KEYMGMT ) const int flags )
{
CRYPT_CERTIFICATE iCryptCert = DUMMY_INIT;
PKCS15_INFO *pkcs15info = keysetInfoPtr->keyData, *pkcs15infoPtr;
MESSAGE_DATA msgData;
BYTE iD[ CRYPT_MAX_HASHSIZE + 8 ];
BOOLEAN certPresent = FALSE, privkeyPresent;
BOOLEAN pkcs15certPresent = FALSE, pkcs15keyPresent = FALSE;
BOOLEAN isCertChain = FALSE, isCertUpdate = FALSE;
const int noPkcs15objects = keysetInfoPtr->keyDataNoObjects;
int pkcs15index = CRYPT_ERROR, iDsize, value, status;
assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
assert( isWritePtr( pkcs15info, \
sizeof( PKCS15_INFO ) * noPkcs15objects ) );
REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS15 );
REQUIRES( isHandleRangeValid( cryptHandle ) );
REQUIRES( itemType == KEYMGMT_ITEM_PUBLICKEY || \
itemType == KEYMGMT_ITEM_PRIVATEKEY || \
itemType == KEYMGMT_ITEM_SECRETKEY );
REQUIRES( ( password == NULL && passwordLength == 0 ) || \
( password != NULL && \
passwordLength >= MIN_NAME_LENGTH && \
passwordLength < MAX_ATTRIBUTE_SIZE ) );
REQUIRES( ( itemType == KEYMGMT_ITEM_PUBLICKEY && \
password == NULL && passwordLength == 0 ) || \
( ( itemType == KEYMGMT_ITEM_PRIVATEKEY || \
itemType == KEYMGMT_ITEM_SECRETKEY ) && \
password != NULL && passwordLength != 0 ) );
REQUIRES( flags == KEYMGMT_FLAG_NONE );
/* If we're being sent a secret key, add it to the PKCS #15 keyset and
exit */
if( itemType == KEYMGMT_ITEM_SECRETKEY )
return( addSecretKey( pkcs15info, noPkcs15objects, cryptHandle ) );
/* Check the object, extract ID information from it, and determine
whether it's a standalone certificate (which produces a PKCS #15
certificate object) or a private-key context (which produces a PKCS
#15 private key object and either a PKCS #15 public-key object (if
there's no certificate present) or a certificate object (if there's
a certificate present)).
Note that we don't allow the addition of standalone public keys
(without corresponding private keys) since file keysets are private-
key keysets and not general-purpose public key exchange mechanisms.
Without this safeguard some users would use them as a general public-
key store in place of database keysets or (more rarely) as a type of
unsigned certificate for exchanging public keys.
In addition allowing the storage of standalone public keys is rather
problematic since they need to have a label attached in order to be
identified so performing a public-key add with a private-key context
would work but performing one with a public-key context would fail.
A certificate update on this public-key-only item would result in the
presence a private-key-labelled certificate, which is even more
strange for users to comprehend. To keep things sensible we
therefore disallow the addition of standalone public keys */
status = krnlSendMessage( cryptHandle, IMESSAGE_CHECK, NULL,
MESSAGE_CHECK_PKC );
if( cryptStatusError( status ) )
return( cryptArgError( status ) ? CRYPT_ARGERROR_NUM1 : status );
setMessageData( &msgData, iD, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_KEYID );
if( cryptStatusError( status ) )
return( status );
iDsize = msgData.length;
privkeyPresent = cryptStatusOK( \
krnlSendMessage( cryptHandle, IMESSAGE_CHECK, NULL,
MESSAGE_CHECK_PKC_PRIVATE ) ) ? TRUE : FALSE;
/* If we're adding a private key make sure that there's a context and a
password present. Conversely if we're adding a public key make sure
that there's no password present. The password-check has already
been performed by the kernel but we perform a second check here just
to be safe. The private-key check can't be performed by the kernel
since it doesn't know the difference between public- and private-key
contexts */
switch( itemType )
{
case KEYMGMT_ITEM_PUBLICKEY:
if( password != NULL )
return( CRYPT_ARGERROR_STR1 );
break;
case KEYMGMT_ITEM_PRIVATEKEY:
if( !privkeyPresent )
{
retExtArg( CRYPT_ARGERROR_NUM1,
( CRYPT_ARGERROR_NUM1, KEYSET_ERRINFO,
"Item being added doesn't contain a private "
"key" ) );
}
if( password == NULL )
return( CRYPT_ARGERROR_STR1 );
break;
default:
retIntError();
}
/* If there's a certificate present make sure that it's something that
can be stored. We don't treat the wrong type as an error since we
can still store the public/private key components even if we don't
store the certificate */
if( cryptStatusOK( \
krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE, &value,
CRYPT_CERTINFO_CERTTYPE ) ) && \
( value == CRYPT_CERTTYPE_CERTIFICATE || \
value == CRYPT_CERTTYPE_CERTCHAIN ) )
{
/* If it's a certificate chain, remember this for later since we may
need to store multiple certificates */
if( value == CRYPT_CERTTYPE_CERTCHAIN )
isCertChain = TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -