📄 pkcs15_wr.c
字号:
/* Check the object and make sure the label of what we're adding
doesn't duplicate the label of an existing object */
status = krnlSendMessage( cryptHandle, 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( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_LABEL );
if( cryptStatusError( status ) )
return( status );
if( findEntry( pkcs15info, 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 */
for( i = 0; i < MAX_PKCS15_OBJECTS; i++ )
if( pkcs15info[ i ].type == PKCS15_SUBTYPE_NONE )
break;
if( i == MAX_PKCS15_OBJECTS )
return( CRYPT_ERROR_OVERFLOW );
pkcs15info = &pkcs15info[ i ];
pkcs15info->type = PKCS15_SUBTYPE_SECRETKEY;
/* This functionality is currently unused */
assert( NOTREACHED );
return( CRYPT_ERROR );
}
/* Add an item to the PKCS #15 keyset */
static int setItemFunction( KEYSET_INFO *keysetInfo,
const CRYPT_HANDLE cryptHandle,
const KEYMGMT_ITEM_TYPE itemType,
const char *password, const int passwordLength,
const int flags )
{
CRYPT_ALGO_TYPE pkcCryptAlgo;
CRYPT_CERTIFICATE iCryptCert;
PKCS15_INFO *pkcs15infoPtr;
RESOURCE_DATA msgData;
BYTE iD[ CRYPT_MAX_HASHSIZE ];
BYTE pubKeyAttributes[ KEYATTR_BUFFER_SIZE ];
BYTE privKeyAttributes[ KEYATTR_BUFFER_SIZE ];
BOOLEAN certPresent = FALSE, privkeyContextPresent;
BOOLEAN pkcs15certPresent = FALSE, pkcs15keyPresent = FALSE;
BOOLEAN isCertChain = FALSE, isCertUpdate = FALSE;
int pubKeyAttributeSize;
int privKeyAttributeSize;
int iDsize, modulusSize, value, status;
/* If we're being sent pre-encoded data or a secret key, add it to the
PKCS #15 data and exit */
if( cryptHandle == CRYPT_UNUSED )
return( addConfigData( keysetInfo->keyData, password, passwordLength,
flags ) );
if( itemType == KEYMGMT_ITEM_SECRETKEY )
return( addSecretKey( keysetInfo->keyData, cryptHandle ) );
/* Check the object, extract ID information from it, and determine
whether it's a standalone cert (which produces a PKCS #15 cert object)
or a private-key context (which produces PKCS #15 a private key object
and either a PKCS #15 public-key object or a cert object) */
status = krnlSendMessage( cryptHandle, IMESSAGE_CHECK, NULL,
MESSAGE_CHECK_PKC );
if( cryptStatusOK( status ) )
{
krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE, &pkcCryptAlgo,
CRYPT_CTXINFO_ALGO );
krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE, &modulusSize,
CRYPT_CTXINFO_KEYSIZE );
setMessageData( &msgData, iD, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_KEYID );
iDsize = msgData.length;
}
if( cryptStatusError( status ) )
return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
CRYPT_ARGERROR_NUM1 : status );
privkeyContextPresent = cryptStatusOK( \
krnlSendMessage( cryptHandle, IMESSAGE_CHECK, NULL,
MESSAGE_CHECK_PKC_PRIVATE ) ) ? TRUE : FALSE;
/* If there's a cert 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
cert */
status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE, &value,
CRYPT_CERTINFO_CERTTYPE );
if( cryptStatusOK( status ) && \
( value == CRYPT_CERTTYPE_CERTIFICATE || \
value == CRYPT_CERTTYPE_CERTCHAIN ) )
{
/* If it's a cert chain, remember this for later since we may
need to store multiple certs */
if( value == CRYPT_CERTTYPE_CERTCHAIN )
isCertChain = TRUE;
/* If the cert isn't signed, we can't store it in this state */
status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE,
&value, CRYPT_CERTINFO_IMMUTABLE );
if( cryptStatusError( status ) || !value )
return( CRYPT_ERROR_NOTINITED );
krnlSendMessage( cryptHandle, IMESSAGE_GETDEPENDENT, &iCryptCert,
OBJECT_TYPE_CERTIFICATE );
certPresent = TRUE;
}
status = CRYPT_OK; /* Reset status from the check above */
/* Find out where we can add data and what needs to be added */
pkcs15infoPtr = findEntry( keysetInfo->keyData, CRYPT_KEYIDEX_ID,
iD, iDsize, KEYMGMT_FLAG_NONE );
if( pkcs15infoPtr != NULL )
{
BOOLEAN unneededCert, unneededKey;
/* Determine what actually needs to be added */
if( pkcs15infoPtr->privKeyData != NULL )
pkcs15keyPresent = TRUE;
if( pkcs15infoPtr->certData != NULL )
pkcs15certPresent = TRUE;
/* Make sure we can update at least one of the PKCS #15 objects in
the personality */
unneededKey = privkeyContextPresent & pkcs15keyPresent;
unneededCert = certPresent & pkcs15certPresent;
if( ( ( unneededCert && !privkeyContextPresent ) || \
( unneededKey && unneededCert ) ) && \
pkcs15infoPtr->validTo != 0 )
{
time_t validTo;
/* If the cert would be a duplicate, see if the new cert is more
recent than the existing one. We only perform this check if
there's a validTo time stored for the cert since without this
restriction any cert without a stored time could be
overwritten */
setMessageData( &msgData, &validTo, sizeof( time_t ) );
status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_VALIDTO );
if( cryptStatusOK( status ) && validTo > pkcs15infoPtr->validTo )
{
time_t validFrom;
/* It's a newer cert, 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 (e.g. cert 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
certs with a date encoded in the DN), and so on an so on).
Because it requires manual processing by a human, we
don't even try and sort it all but just allow a cert for
a given key (checked by the ID match) to be replaced by a
newer cert 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 is one special-case situation in which odd things
can happen when updating certs and that's when adding a
future-dated cert, which would result in the cert 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 certs it's likely that
the hit-and-miss cert checking performed by most software
won't even notice a future-dated cert, and for signature
certs the semantics of signing data now using a cert 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 a future-dated cert */
setMessageData( &msgData, &validFrom, sizeof( time_t ) );
status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_VALIDFROM );
if( cryptStatusOK( status ) && \
validFrom > getApproxTime() + 86400 )
{
assert( !"Attempt to replace cert with future-dated cert" );
}
}
}
if( ( unneededKey && !certPresent ) || /* Key only, duplicate */
( unneededCert && !privkeyContextPresent ) || /* Cert only, duplicate */
( unneededKey && unneededCert ) ) /* Key+cert, duplicate */
{
/* If it's anything other than a cert chain, we can't add
anything */
if( !isCertChain )
return( CRYPT_ERROR_DUPLICATE );
/* It's a cert chain, there may be new certs present, try and add
them */
status = krnlSendMessage( cryptHandle, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_TRUE,
CRYPT_IATTRIBUTE_LOCKED );
if( cryptStatusError( status ) )
return( status );
status = addCertChain( pkcs15infoPtr, cryptHandle );
krnlSendMessage( cryptHandle, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_FALSE, CRYPT_IATTRIBUTE_LOCKED );
return( status );
}
}
else
{
char label[ CRYPT_MAX_TEXTSIZE + 1 ];
int i;
/* This key/cert isn't already present, make sure the label of what
we're adding doesn't duplicate the label of an existing object */
if( privkeyContextPresent )
{
setMessageData( &msgData, label, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_LABEL );
if( cryptStatusError( status ) )
return( status );
}
if( findEntry( keysetInfo->keyData, 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 = keysetInfo->keyData;
for( i = 0; i < MAX_PKCS15_OBJECTS; i++ )
if( pkcs15infoPtr[ i ].type == PKCS15_SUBTYPE_NONE )
break;
if( i == MAX_PKCS15_OBJECTS )
return( CRYPT_ERROR_OVERFLOW );
pkcs15infoPtr = &pkcs15infoPtr[ i ];
pkcs15infoPtr->index = i;
}
pkcs15infoPtr->type = PKCS15_SUBTYPE_NORMAL;
/* If we're adding a private key, make sure there's a context and a
password present. Conversely, if there's a password present make
sure that we're adding a private key. This has already been checked
by the kernel, but we perform a second check here just to be safe */
if( itemType == KEYMGMT_ITEM_PRIVATEKEY )
{
if( !privkeyContextPresent )
return( CRYPT_ARGERROR_NUM1 );
if( password == NULL )
return( CRYPT_ARGERROR_STR1 );
}
else
if( password != NULL )
return( CRYPT_ARGERROR_NUM1 );
/* We're ready to go, lock the object for our exclusive use */
if( certPresent )
{
status = krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_TRUE,
CRYPT_IATTRIBUTE_LOCKED );
if( cryptStatusError( status ) )
return( status );
}
/* Write the attribute information. We have to rewrite the key
information when we add a non-standalone cert even if we don't change
the key because adding a cert can affect key attributes */
if( ( certPresent && pkcs15keyPresent ) || /* Updating existing */
( privkeyContextPresent && !pkcs15keyPresent ) ) /* Adding new */
status = writeKeyAttributes( privKeyAttributes, &privKeyAttributeSize,
pubKeyAttributes, &pubKeyAttributeSize,
pkcs15infoPtr, cryptHandle );
if( cryptStatusError( status ) )
{
if( certPresent )
krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_FALSE, CRYPT_IATTRIBUTE_LOCKED );
return( status );
}
/* Write the cert if necessary. We do this one first because it's the
easiest to back out of */
if( certPresent && ( isCertUpdate || !pkcs15certPresent ) )
{
/* Select the leaf cert in case it's a cert chain */
krnlSendMessage( cryptHandle, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_CURSORFIRST,
CRYPT_CERTINFO_CURRENT_CERTIFICATE );
/* Write the cert information. There may be further certs in the
chain but we don't try and do anything with these until after the
rest of the key information has been added */
status = addCert( pkcs15infoPtr, cryptHandle, pubKeyAttributes,
pubKeyAttributeSize, privKeyAttributes,
privKeyAttributeSize, pkcs15keyPresent ? \
CERTADD_UPDATE_EXISTING : \
privkeyContextPresent ? \
CERTADD_NORMAL : CERTADD_STANDALONE_CERT );
if( cryptStatusError( status ) )
{
if( certPresent )
krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_FALSE,
CRYPT_IATTRIBUTE_LOCKED );
return( status );
}
/* If there's no context to add we return now, however if we've been
given a cert chain with further certs in it we try and add these as
well before we exit. Note that we may return an error at this
point if the cert chain update fails even if the main cert add
succeeded. This is better than returning CRYPT_OK but only adding
some certs since it lets the caller know the operation wasn't
completely successful and can be retried if necessary, at which
point it'll be handled via the cert-chain-only update code earlier
on */
if( !privkeyContextPresent || pkcs15keyPresent )
{
if( isCertChain )
status = addCertChain( pkcs15infoPtr, cryptHandle );
if( certPresent )
krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_FALSE,
CRYPT_IATTRIBUTE_LOCKED );
return( status );
}
}
assert( itemType == KEYMGMT_ITEM_PRIVATEKEY );
assert( !isCertUpdate );
/* Add the public k
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -