📄 pkcs15.c
字号:
/****************************************************************************
* *
* cryptlib PKCS #15 Routines *
* Copyright Peter Gutmann 1996-2003 *
* *
****************************************************************************/
/* The format used to protect the private key components is a standard
cryptlib envelope, however for various reasons the required enveloping
functionality (which in practice is just minimal code to process a
PasswordRecipientInfo at the start of the data) is duplicated here:
1. It's somewhat inelegant to use the heavyweight enveloping routines to
wrap up 100 bytes of data.
2. The enveloping code is enormous and complex, especially when extra
sections like zlib and PGP and S/MIME support are factored in. This
makes it difficult to compile a stripped-down version of cryptlib,
since private key storage will require all the enveloping code to be
included.
3. Since the enveloping code is general-purpose, it doesn't allow very
precise control over the data being processed. Specifically, it's
necessary to write the private key components to a buffer in plaintext
form, which isn't permitted by the cryptlib kernel.
For these reasons this module includes the code to process minimal
(password-encrypted data) envelopes */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
#include "crypt.h"
#include "keyset.h"
#include "pkcs15.h"
#include "asn1.h"
#include "asn1_ext.h"
#elif defined( INC_CHILD )
#include "../crypt.h"
#include "keyset.h"
#include "pkcs15.h"
#include "../misc/asn1.h"
#include "../misc/asn1_ext.h"
#else
#include "crypt.h"
#include "keyset/keyset.h"
#include "keyset/pkcs15.h"
#include "misc/asn1.h"
#include "misc/asn1_ext.h"
#endif /* Compiler-specific includes */
#ifdef USE_PKCS15
/* OID information used to read a PKCS #15 file */
static const FAR_BSS CMS_CONTENT_INFO oidInfoPkcs15Data = { 0, 0 };
static const FAR_BSS OID_INFO keyFileOIDinfo[] = {
{ OID_PKCS15_CONTENTTYPE, CRYPT_OK, &oidInfoPkcs15Data },
{ NULL, 0 }
};
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Locate an object based on an ID */
#define matchID( src, srcLen, dest, destLen ) \
( ( srcLen ) == ( destLen ) && \
!memcmp( ( src ), ( dest ), ( destLen ) ) )
PKCS15_INFO *findEntry( const PKCS15_INFO *pkcs15info,
const CRYPT_KEYID_TYPE keyIDtype,
const void *keyID, const int keyIDlength,
const int requestedUsage )
{
int i;
assert( isReadPtr( pkcs15info, sizeof( PKCS15_INFO ) * \
MAX_PKCS15_OBJECTS ) );
assert( keyIDlength == 0 || isReadPtr( keyID, keyIDlength ) );
assert( ( requestedUsage & KEYMGMT_MASK_USAGEOPTIONS ) != \
KEYMGMT_MASK_USAGEOPTIONS );
/* If there's no ID to search on, don't try and do anything (this can
occur when we're trying to build a chain and the necessary chaining
data isn't present) */
if( keyIDlength == 0 )
return( NULL );
/* Try and locate the appropriate object in the PKCS #15 collection */
for( i = 0; i < MAX_PKCS15_OBJECTS; i++ )
{
const PKCS15_INFO *pkcs15infoPtr = &pkcs15info[ i ];
const int compositeUsage = pkcs15infoPtr->pubKeyUsage | \
pkcs15infoPtr->privKeyUsage;
/* If there's no entry at this position, continue */
if( pkcs15infoPtr->type == PKCS15_SUBTYPE_NONE )
continue;
/* If there's an explicit usage requested, make sure the key usage
matches this. This can get slightly complex since the advertised
usage isn't necessarily the same as the usage permitted by the
associated cert (PKCS #11 apps are particularly good at setting
bogus usage types) and the overall result can be further
influenced by trusted usage settings, all we check for here is
an indicated usage for the key matching the requested usage */
if( ( requestedUsage & KEYMGMT_FLAG_USAGE_CRYPT ) && \
!( compositeUsage & ENCR_USAGE_MASK ) )
continue;
if( ( requestedUsage & KEYMGMT_FLAG_USAGE_SIGN ) && \
!( compositeUsage & SIGN_USAGE_MASK ) )
continue;
/* Check for a match based on the ID type */
switch( keyIDtype )
{
case CRYPT_KEYID_NAME:
case CRYPT_KEYID_URI:
if( matchID( pkcs15infoPtr->label, pkcs15infoPtr->labelLength,
keyID, keyIDlength ) )
return( ( PKCS15_INFO * ) pkcs15infoPtr );
break;
case CRYPT_IKEYID_KEYID:
if( matchID( pkcs15infoPtr->keyID, pkcs15infoPtr->keyIDlength,
keyID, keyIDlength ) )
return( ( PKCS15_INFO * ) pkcs15infoPtr );
break;
case CRYPT_IKEYID_PGPKEYID:
if( matchID( pkcs15infoPtr->pgp2KeyID,
pkcs15infoPtr->pgp2KeyIDlength, keyID,
keyIDlength ) )
return( ( PKCS15_INFO * ) pkcs15infoPtr );
break;
case CRYPT_IKEYID_ISSUERID:
if( matchID( pkcs15infoPtr->iAndSID,
pkcs15infoPtr->iAndSIDlength, keyID,
keyIDlength ) )
return( ( PKCS15_INFO * ) pkcs15infoPtr );
break;
case CRYPT_KEYIDEX_ID:
if( matchID( pkcs15infoPtr->iD, pkcs15infoPtr->iDlength,
keyID, keyIDlength ) )
return( ( PKCS15_INFO * ) pkcs15infoPtr );
break;
case CRYPT_KEYIDEX_SUBJECTNAMEID:
if( matchID( pkcs15infoPtr->subjectNameID,
pkcs15infoPtr->subjectNameIDlength, keyID,
keyIDlength ) )
return( ( PKCS15_INFO * ) pkcs15infoPtr );
break;
default:
assert( NOTREACHED );
}
}
/* If we're trying to match on the PGP key ID and didn't find anything,
retry it using the first PGP_KEYID_SIZE bytes of the object ID. This
is necessary because calculation of the OpenPGP ID requires the
presence of data that may not be present in non-PGP keys, so we can't
calculate a real OpenPGP ID but have to use the next-best thing */
if( keyIDtype == CRYPT_IKEYID_PGPKEYID )
for( i = 0; i < MAX_PKCS15_OBJECTS; i++ )
if( pkcs15info[ i ].iDlength >= PGP_KEYID_SIZE && \
!memcmp( keyID, pkcs15info[ i ].iD, PGP_KEYID_SIZE ) )
return( ( PKCS15_INFO * ) &pkcs15info[ i ] );
return( NULL );
}
/* Free object entries */
void pkcs15freeEntry( PKCS15_INFO *pkcs15info )
{
if( pkcs15info->pubKeyData != NULL )
{
zeroise( pkcs15info->pubKeyData, pkcs15info->pubKeyDataSize );
clFree( "pkcs15freeEntry", pkcs15info->pubKeyData );
}
if( pkcs15info->privKeyData != NULL )
{
zeroise( pkcs15info->privKeyData, pkcs15info->privKeyDataSize );
clFree( "pkcs15freeEntry", pkcs15info->privKeyData );
}
if( pkcs15info->certData != NULL )
{
zeroise( pkcs15info->certData, pkcs15info->certDataSize );
clFree( "pkcs15freeEntry", pkcs15info->certData );
}
if( pkcs15info->dataData != NULL )
{
zeroise( pkcs15info->dataData, pkcs15info->dataDataSize );
clFree( "pkcs15freeEntry", pkcs15info->dataData );
}
zeroise( pkcs15info, sizeof( PKCS15_INFO ) );
}
void pkcs15Free( PKCS15_INFO *pkcs15info )
{
int i;
assert( isWritePtr( pkcs15info, sizeof( PKCS15_INFO ) * \
MAX_PKCS15_OBJECTS ) );
for( i = 0; i < MAX_PKCS15_OBJECTS; i++ )
pkcs15freeEntry( &pkcs15info[ i ] );
zeroise( pkcs15info, sizeof( PKCS15_INFO ) * MAX_PKCS15_OBJECTS );
}
/* Get the PKCS #15 validity information from a certificate */
int getValidityInfo( PKCS15_INFO *pkcs15info,
const CRYPT_HANDLE cryptHandle )
{
RESOURCE_DATA msgData;
time_t validFrom, validTo;
int status;
/* Remember the validity information for later. Note that we always
update the validity (even if it's already set) since we may be
replacing an older cert with a newer one */
setMessageData( &msgData, &validFrom, sizeof( time_t ) );
status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_VALIDFROM );
setMessageData( &msgData, &validTo, sizeof( time_t ) );
if( cryptStatusOK( status ) )
status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_VALIDTO );
if( cryptStatusError( status ) )
{
/* There wasn't any standard validity info present, try for PGP
validity info */
setMessageData( &msgData, &validFrom, sizeof( time_t ) );
status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_PGPVALIDITY );
validTo = 0;
}
if( cryptStatusError( status ) )
return( status );
if( pkcs15info->validTo > validTo )
/* There's an existing, newer cert already present, make sure we
don't try and add the new one */
return( CRYPT_ERROR_DUPLICATE );
pkcs15info->validFrom = validFrom;
pkcs15info->validTo = validTo;
return( CRYPT_OK );
}
/****************************************************************************
* *
* PKCS #15 Init Functions *
* *
****************************************************************************/
/* A PKCS #15 keyset can contain multiple keys and whatnot, so when we open
it we parse the contents into memory for later use */
static int initFunction( KEYSET_INFO *keysetInfo, const char *name,
const CRYPT_KEYOPT_TYPE options )
{
PKCS15_INFO *pkcs15info;
long endPos;
int status;
assert( name == NULL );
/* If we're opening an existing keyset, skip the outer header, optional
keyManagementInfo, and inner header. We do this before we perform any
setup operations to weed out potential problem files */
if( options != CRYPT_KEYOPT_CREATE )
{
STREAM *stream = &keysetInfo->keysetFile->stream;
long dataEndPos;
status = readCMSheader( stream, keyFileOIDinfo, &dataEndPos, FALSE );
if( cryptStatusError( status ) )
return( status );
endPos = dataEndPos + ( stell( stream ) - sizeofShortInteger( 0 ) );
if( dataEndPos < 16 || dataEndPos > MAX_INTLENGTH || \
endPos < 16 || endPos > MAX_INTLENGTH )
/* Make sure that the length info is sensible */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -