📄 pkcs15_rd.c
字号:
/****************************************************************************
* *
* cryptlib PKCS #15 Read Routines *
* Copyright Peter Gutmann 1996-2004 *
* *
****************************************************************************/
#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
/* The minimum size of an object in a keyset, used for sanity-checking when
reading a keyset */
#define MIN_OBJECT_SIZE 16
/* OID information used to read a PKCS #15 file */
static const FAR_BSS OID_INFO dataOIDinfo[] = {
{ OID_CMS_DATA, CRYPT_OK },
{ NULL, 0 }
};
static const FAR_BSS OID_INFO cryptlibDataOIDinfo[] = {
{ OID_CRYPTLIB_CONFIGDATA, CRYPT_IATTRIBUTE_CONFIGDATA },
{ OID_CRYPTLIB_USERINDEX, CRYPT_IATTRIBUTE_USERINDEX },
{ OID_CRYPTLIB_USERINFO, CRYPT_IATTRIBUTE_USERINFO },
{ NULL, 0 }
};
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Translate the PKCS #15 usage flags into cryptlib permitted actions. The
PKCS #11 use of the 'derive' flag to mean 'allow key agreement' is a bit
of a kludge, we map it to allowing keyagreement export and import if it's
a key-agreement algorithm, if there are further constraints they'll be
handled by the attached cert. The PKCS #15 nonRepudiation flag doesn't
have any definition so we can't do anything with it, although we may need
to translate it to allowing signing and/or verification if implementations
appear that expect it to be used this way */
static int getPermittedActions( const int usageFlags,
const CRYPT_ALGO_TYPE cryptAlgo )
{
int actionFlags = 0;
if( usageFlags & ( PKCS15_USAGE_ENCRYPT | PKCS15_USAGE_WRAP ) )
actionFlags |= MK_ACTION_PERM( MESSAGE_CTX_ENCRYPT, ACTION_PERM_ALL );
if( usageFlags & ( PKCS15_USAGE_DECRYPT | PKCS15_USAGE_UNWRAP ) )
actionFlags |= MK_ACTION_PERM( MESSAGE_CTX_DECRYPT, ACTION_PERM_ALL );
if( usageFlags & PKCS15_USAGE_SIGN )
actionFlags |= MK_ACTION_PERM( MESSAGE_CTX_SIGN, ACTION_PERM_ALL );
if( usageFlags & PKCS15_USAGE_VERIFY )
actionFlags |= MK_ACTION_PERM( MESSAGE_CTX_SIGCHECK, ACTION_PERM_ALL );
if( isKeyxAlgo( cryptAlgo ) && ( usageFlags & PKCS15_USAGE_DERIVE ) )
actionFlags |= MK_ACTION_PERM( MESSAGE_CTX_ENCRYPT, ACTION_PERM_ALL ) | \
MK_ACTION_PERM( MESSAGE_CTX_DECRYPT, ACTION_PERM_ALL );
if( cryptAlgo == CRYPT_ALGO_RSA )
{
/* If there are any restrictions on the key usage, we have to make it
internal-only because of RSA's signature/encryption duality */
if( !( ( usageFlags & ( PKCS15_USAGE_ENCRYPT | PKCS15_USAGE_WRAP | \
PKCS15_USAGE_DECRYPT | PKCS15_USAGE_UNWRAP ) ) && \
( usageFlags & ( PKCS15_USAGE_SIGN | PKCS15_USAGE_VERIFY ) ) ) )
actionFlags = MK_ACTION_PERM_NONE_EXTERNAL( actionFlags );
}
else
/* Because of the special-case data formatting requirements for DLP
algorithms, we make the usage internal-only */
actionFlags = MK_ACTION_PERM_NONE_EXTERNAL( actionFlags );
return( !actionFlags ? CRYPT_ERROR_PERMISSION : actionFlags );
}
/****************************************************************************
* *
* Read PKCS #15 Attributes *
* *
****************************************************************************/
/* Read a sequence of PKCS #15 key identifiers */
static int readKeyIdentifiers( STREAM *stream, PKCS15_INFO *pkcs15info,
const int length )
{
const int endPos = stell( stream ) + length;
int status = CRYPT_OK;
while( cryptStatusOK( status ) && stell( stream ) < endPos )
{
HASHFUNCTION hashFunction;
void *iAndSPtr;
long value;
int hashSize, payloadLength, iAndSLength;
/* Read each identifier type and copy the useful ones into the PKCS
#15 info */
readSequence( stream, &payloadLength );
status = readShortInteger( stream, &value );
if( cryptStatusError( status ) )
break;
switch( value )
{
case PKCS15_KEYID_ISSUERANDSERIALNUMBER:
/* Hash the full issuerAndSerialNumber to get an iAndSID */
getHashParameters( CRYPT_ALGO_SHA, &hashFunction, &hashSize );
iAndSPtr = sMemBufPtr( stream );
status = readSequence( stream, &iAndSLength );
if( cryptStatusOK( status ) )
status = sSkip( stream, iAndSLength );
if( cryptStatusError( status ) )
break;
hashFunction( NULL, ( BYTE * ) pkcs15info->iAndSID, iAndSPtr,
( int ) sizeofObject( iAndSLength ), HASH_ALL );
pkcs15info->iAndSIDlength = hashSize;
break;
case PKCS15_KEYID_SUBJECTKEYIDENTIFIER:
status = readOctetString( stream, pkcs15info->keyID,
&pkcs15info->keyIDlength, CRYPT_MAX_HASHSIZE );
break;
case PKCS15_KEYID_ISSUERANDSERIALNUMBERHASH:
/* If we've already got the iAndSID by hashing the
issuerAndSerialNumber, use that version instead */
if( pkcs15info->iAndSIDlength )
{
readUniversal( stream );
continue;
}
status = readOctetString( stream, pkcs15info->iAndSID,
&pkcs15info->iAndSIDlength, KEYID_SIZE );
break;
case PKCS15_KEYID_ISSUERNAMEHASH:
status = readOctetString( stream, pkcs15info->issuerNameID,
&pkcs15info->issuerNameIDlength, KEYID_SIZE );
break;
case PKCS15_KEYID_SUBJECTNAMEHASH:
status = readOctetString( stream, pkcs15info->subjectNameID,
&pkcs15info->subjectNameIDlength, KEYID_SIZE );
break;
case PKCS15_KEYID_PGP2:
status = readOctetString( stream, pkcs15info->pgp2KeyID,
&pkcs15info->pgp2KeyIDlength, PGP_KEYID_SIZE );
break;
case PKCS15_KEYID_OPENPGP:
status = readOctetString( stream, pkcs15info->openPGPKeyID,
&pkcs15info->openPGPKeyIDlength, PGP_KEYID_SIZE );
break;
default:
status = readUniversal( stream );
}
}
return( status );
}
/* Read an object's attributes */
static int readObjectAttributes( STREAM *stream, PKCS15_INFO *pkcs15info,
const PKCS15_OBJECT_TYPE type )
{
int length, endPos, status;
/* Clear the return value */
memset( pkcs15info, 0, sizeof( PKCS15_INFO ) );
/* Skip the outer header, which has already been checked when we read in
the object data */
readGenericHole( stream, NULL, DEFAULT_TAG );
/* Process the PKCS15CommonObjectAttributes */
status = readSequence( stream, &length );
if( cryptStatusOK( status ) && length > 0 )
{
endPos = stell( stream ) + length;
/* Read the label if it's present and skip anything else */
if( peekTag( stream ) == BER_STRING_UTF8 )
status = readCharacterString( stream,
( BYTE * ) pkcs15info->label, &pkcs15info->labelLength,
CRYPT_MAX_TEXTSIZE, BER_STRING_UTF8 );
if( cryptStatusOK( status ) && stell( stream ) < endPos )
status = sseek( stream, endPos );
}
if( cryptStatusError( status ) )
return( status );
/* Process the PKCS15CommonXXXAttributes */
readSequence( stream, &length );
endPos = stell( stream ) + length;
if( type == PKCS15_OBJECT_DATA )
{
/* It's a data object, make sure it's one of ours */
status = readFixedOID( stream, OID_CRYPTLIB_CONTENTTYPE );
if( cryptStatusOK( status ) && stell( stream ) < endPos )
status = sseek( stream, endPos );
}
else
{
/* It's a key or cert object, read the ID and assorted flags */
status = readOctetString( stream, pkcs15info->iD,
&pkcs15info->iDlength, CRYPT_MAX_HASHSIZE );
if( cryptStatusError( status ) )
return( status );
if( type == PKCS15_OBJECT_PUBKEY || type == PKCS15_OBJECT_PRIVKEY )
{
int usageFlags;
readBitString( stream, &usageFlags ); /* Usage flags */
if( peekTag( stream ) == BER_BOOLEAN ) /* Native flag */
status = readUniversal( stream );
if( stell( stream ) < endPos && /* Access flags */
peekTag( stream ) == BER_BITSTRING )
status = readUniversal( stream );
if( stell( stream ) < endPos && /* Key reference */
peekTag( stream ) == BER_INTEGER )
status = readUniversal( stream );
if( stell( stream ) < endPos && /* Start date */
peekTag( stream ) == BER_TIME_GENERALIZED )
status = readGeneralizedTime( stream,
&pkcs15info->validFrom );
if( stell( stream ) < endPos && /* End date */
peekTag( stream ) == MAKE_CTAG( CTAG_KA_VALIDTO ) )
status = readGeneralizedTimeTag( stream,
&pkcs15info->validTo, CTAG_KA_VALIDTO );
if( type == PKCS15_OBJECT_PUBKEY )
pkcs15info->pubKeyUsage = usageFlags;
else
pkcs15info->privKeyUsage = usageFlags;
}
else
if( type == PKCS15_OBJECT_CERT )
{
if( peekTag( stream ) == BER_BOOLEAN ) /* Authority flag */
status = readUniversal( stream );
if( stell( stream ) < endPos && /* Identifier */
peekTag( stream ) == BER_SEQUENCE )
status = readUniversal( stream );
if( stell( stream ) < endPos && /* Thumbprint */
peekTag( stream ) == MAKE_CTAG( CTAG_CA_DUMMY ) )
status = readUniversal( stream );
if( stell( stream ) < endPos && /* Trusted usage */
peekTag( stream ) == MAKE_CTAG( CTAG_CA_TRUSTED_USAGE ) )
{
readConstructed( stream, NULL, CTAG_CA_TRUSTED_USAGE );
status = readBitString( stream, &pkcs15info->trustedUsage );
}
if( stell( stream ) < endPos && /* Identifiers */
peekTag( stream ) == MAKE_CTAG( CTAG_CA_IDENTIFIERS ) )
{
status = readConstructed( stream, &length,
CTAG_CA_IDENTIFIERS );
if( cryptStatusOK( status ) )
status = readKeyIdentifiers( stream, pkcs15info,
length );
}
if( stell( stream ) < endPos && /* Implicitly trusted */
peekTag( stream ) == \
MAKE_CTAG_PRIMITIVE( CTAG_CA_TRUSTED_IMPLICIT ) )
status = readBooleanTag( stream,
&pkcs15info->implicitTrust,
CTAG_CA_TRUSTED_IMPLICIT );
if( peekTag( stream ) == MAKE_CTAG( CTAG_CA_VALIDTO ) )
{
/* Due to miscommunication between PKCS #15 and 7816-15,
there are two ways to encode the validity information
for certs, one based on the format used elsewhere in
PKCS #15 (for PKCS #15) and the other based on the
format used in certs (for 7816-15). Luckily they can
be distinguished by the tagging type */
readConstructed( stream, NULL, CTAG_CA_VALIDTO );
readUTCTime( stream, &pkcs15info->validFrom );
status = readUTCTime( stream, &pkcs15info->validTo );
}
else
{
if( stell( stream ) < endPos && /* Start date */
peekTag( stream ) == BER_TIME_GENERALIZED )
status = readGeneralizedTime( stream,
&pkcs15info->validFrom );
if( stell( stream ) < endPos && /* End date */
peekTag( stream ) == MAKE_CTAG_PRIMITIVE( CTAG_CA_VALIDTO ) )
status = readGeneralizedTimeTag( stream,
&pkcs15info->validTo,
CTAG_CA_VALIDTO );
}
}
if( cryptStatusOK( status ) && stell( stream ) < endPos )
status = sseek( stream, endPos );
}
if( cryptStatusError( status ) )
return( status );
/* For now we use the iD as the keyID, this may be overridden later if
there's a real keyID present */
memcpy( pkcs15info->keyID, pkcs15info->iD, pkcs15info->iDlength );
pkcs15info->keyIDlength = pkcs15info->iDlength;
/* Skip the public/private key attributes if present */
if( peekTag( stream ) == MAKE_CTAG( CTAG_OB_SUBCLASSATTR ) )
status = readUniversal( stream );
if( cryptStatusError( status ) )
return( status );
/* Process the type attributes, which just consists of remembering where
the payload starts */
readConstructed( stream, NULL, CTAG_OB_TYPEATTR );
status = readSequence( stream, &length );
endPos = stell( stream ) + length;
if( cryptStatusOK( status ) )
{
int value;
switch( type )
{
case PKCS15_OBJECT_PUBKEY:
readConstructed( stream, NULL, CTAG_OV_DIRECT );
pkcs15info->pubKeyOffset = stell( stream );
break;
case PKCS15_OBJECT_PRIVKEY:
pkcs15info->privKeyOffset = stell( stream );
break;
case PKCS15_OBJECT_CERT:
case PKCS15_OBJECT_TRUSTEDCERT:
case PKCS15_OBJECT_USEFULCERT:
pkcs15info->certOffset = stell( stream );
break;
case PKCS15_OBJECT_DATA:
readOID( stream, cryptlibDataOIDinfo, &value );
if( value != CRYPT_IATTRIBUTE_USERINFO )
/* UserInfo is a straight object, the others are
SEQUENCEs of objects */
readSequence( stream, NULL );
pkcs15info->dataType = value;
pkcs15info->dataOffset = stell( stream );
break;
}
if( cryptStatusOK( status ) && stell( stream ) < endPos )
status = sseek( stream, endPos );
}
return( status );
}
/* Read an entire keyset */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -