Пример #1
0
	KEY_TYPE_LAST			/* Last possible key type */
	} KEY_TYPE;

/* A structure to store key type-related information, indexed by the KEY_TYPE 
   value */

static const struct {
	const char *label;		/* Label for private key */
	const int labelLength;
	const int actionPerms;	/* Context action perms */
	const int keyUsage;		/* Certificate key usage */
	} keyInfo[] = {
	{ NULL, 0,				/* KEY_TYPE_NONE */
		0, CRYPT_KEYUSAGE_NONE },
	{ "Encryption key", 14,	/* KEY_TYPE_ENCRYPTION */
		MK_ACTION_PERM( MESSAGE_CTX_ENCRYPT, ACTION_PERM_NONE_EXTERNAL ) | \
		MK_ACTION_PERM( MESSAGE_CTX_DECRYPT, ACTION_PERM_NONE_EXTERNAL ),
		CRYPT_KEYUSAGE_KEYENCIPHERMENT },
	{ "Signature key", 13,	/* KEY_TYPE_SIGNATURE */
		MK_ACTION_PERM( MESSAGE_CTX_SIGN, ACTION_PERM_NONE_EXTERNAL ) | \
		MK_ACTION_PERM( MESSAGE_CTX_SIGCHECK, ACTION_PERM_NONE_EXTERNAL ),
		CRYPT_KEYUSAGE_DIGITALSIGNATURE },
	{ "Private key", 11,	/* KEY_TYPE_BOTH */
		MK_ACTION_PERM( MESSAGE_CTX_ENCRYPT, ACTION_PERM_NONE_EXTERNAL ) | \
		MK_ACTION_PERM( MESSAGE_CTX_DECRYPT, ACTION_PERM_NONE_EXTERNAL ) | \
		MK_ACTION_PERM( MESSAGE_CTX_SIGN, ACTION_PERM_NONE_EXTERNAL ) | \
		MK_ACTION_PERM( MESSAGE_CTX_SIGCHECK, ACTION_PERM_NONE_EXTERNAL ),
		CRYPT_KEYUSAGE_KEYENCIPHERMENT | CRYPT_KEYUSAGE_DIGITALSIGNATURE },
	{ NULL, 0, 0, CRYPT_KEYUSAGE_NONE }, { NULL, 0, 0, CRYPT_KEYUSAGE_NONE }
	};
Пример #2
0
static int readRsaPrivateKeyOld( INOUT STREAM *stream, 
								 INOUT CONTEXT_INFO *contextInfoPtr )
	{
	CRYPT_ALGO_TYPE cryptAlgo;
	PKC_INFO *rsaKey = contextInfoPtr->ctxPKC;
	const int startPos = stell( stream );
	int length, endPos, iterationCount, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );

	REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \
			  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_RSA );

	/* Skip the PKCS #8 wrapper.  When we read the OCTET STRING 
	   encapsulation we use MIN_PKCSIZE_THRESHOLD rather than MIN_PKCSIZE
	   so that a too-short key will get to readBignumChecked(), which
	   returns an appropriate error code */
	readSequence( stream, &length );	/* Outer wrapper */
	readShortInteger( stream, NULL );	/* Version */
	status = readAlgoID( stream, &cryptAlgo, ALGOID_CLASS_PKC );
	if( cryptStatusError( status ) || cryptAlgo != CRYPT_ALGO_RSA )
		return( CRYPT_ERROR_BADDATA );
	status = readOctetStringHole( stream, NULL, 
								  ( 2 * MIN_PKCSIZE_THRESHOLD ) + \
									( 5 * ( MIN_PKCSIZE_THRESHOLD / 2 ) ), 
								  DEFAULT_TAG );
	if( cryptStatusError( status ) )	/* OCTET STRING encapsulation */
		return( status );

	/* Read the header */
	readSequence( stream, NULL );
	status = readShortInteger( stream, NULL );
	if( cryptStatusError( status ) )
		return( status );

	/* Read the RSA key components, skipping n and e if we've already got 
	   them via the associated public key/certificate */
	if( BN_is_zero( &rsaKey->rsaParam_n ) )
		{
		status = readBignumChecked( stream, &rsaKey->rsaParam_n,
									RSAPARAM_MIN_N, RSAPARAM_MAX_N, 
									NULL );
		if( cryptStatusOK( status ) )
			status = readBignum( stream, &rsaKey->rsaParam_e,
								 RSAPARAM_MIN_E, RSAPARAM_MAX_E,
								 &rsaKey->rsaParam_n );
		}
	else
		{
		readUniversal( stream );
		status = readUniversal( stream );
		}
	if( cryptStatusOK( status ) )
		{
		/* d isn't used so we skip it */
		status = readUniversal( stream );
		}
	if( cryptStatusOK( status ) )
		status = readBignum( stream, &rsaKey->rsaParam_p,
							 RSAPARAM_MIN_P, RSAPARAM_MAX_P,
							 &rsaKey->rsaParam_n );
	if( cryptStatusOK( status ) )
		status = readBignum( stream, &rsaKey->rsaParam_q,
							 RSAPARAM_MIN_Q, RSAPARAM_MAX_Q,
							 &rsaKey->rsaParam_n );
	if( cryptStatusOK( status ) )
		status = readBignum( stream, &rsaKey->rsaParam_exponent1,
							 RSAPARAM_MIN_EXP1, RSAPARAM_MAX_EXP1,
							 &rsaKey->rsaParam_n );
	if( cryptStatusOK( status ) )
		status = readBignum( stream, &rsaKey->rsaParam_exponent2,
							 RSAPARAM_MIN_EXP2, RSAPARAM_MAX_EXP2,
							 &rsaKey->rsaParam_n );
	if( cryptStatusOK( status ) )
		status = readBignum( stream, &rsaKey->rsaParam_u,
							 RSAPARAM_MIN_U, RSAPARAM_MAX_U,
							 &rsaKey->rsaParam_n );
	if( cryptStatusError( status ) )
		return( status );

	/* Check whether there are any attributes present */
	if( stell( stream ) >= startPos + length )
		return( CRYPT_OK );

	/* Read the attribute wrapper */
	status = readConstructed( stream, &length, 0 );
	if( cryptStatusError( status ) )
		return( status );
	endPos = stell( stream ) + length;

	/* Read the collection of attributes.  Unlike any other key-storage 
	   format, PKCS #8 stores the key usage information as an X.509 
	   attribute alongside the encrypted private key data so we have to
	   process whatever attributes may be present in order to find the
	   keyUsage (if there is any) in order to set the object action 
	   permissions */
	for( iterationCount = 0;
		 stell( stream ) < endPos && \
			iterationCount < FAILSAFE_ITERATIONS_MED;
		 iterationCount++ )
		{
		BYTE oid[ MAX_OID_SIZE + 8 ];
		int oidLength, actionFlags, value;

		/* Read the attribute.  Since there's only one attribute type that 
		   we can use, we hardcode the read in here rather than performing a 
		   general-purpose attribute read */
		readSequence( stream, NULL );
		status = readEncodedOID( stream, oid, MAX_OID_SIZE, &oidLength, 
								 BER_OBJECT_IDENTIFIER );
		if( cryptStatusError( status ) )
			return( status );

		/* If it's not a key-usage attribute, we can't do much with it */
		if( oidLength != sizeofOID( OID_X509_KEYUSAGE ) || \
			memcmp( oid, OID_X509_KEYUSAGE, oidLength ) )
			{
			status = readUniversal( stream );
			if( cryptStatusError( status ) )
				return( status );
			continue;
			}

		/* Read the keyUsage attribute and convert it into cryptlib action 
		   permissions */
		readSet( stream, NULL );
		status = readBitString( stream, &value );
		if( cryptStatusError( status ) )
			return( status );
		actionFlags = ACTION_PERM_NONE;
		if( value & ( KEYUSAGE_SIGN | KEYUSAGE_CA ) )
			{
			actionFlags |= MK_ACTION_PERM( MESSAGE_CTX_SIGN, \
										   ACTION_PERM_ALL ) | \
						   MK_ACTION_PERM( MESSAGE_CTX_SIGCHECK, \
										   ACTION_PERM_ALL );
			}
		if( value & KEYUSAGE_CRYPT )
			{
			actionFlags |= MK_ACTION_PERM( MESSAGE_CTX_ENCRYPT, \
										   ACTION_PERM_ALL ) | \
						   MK_ACTION_PERM( MESSAGE_CTX_DECRYPT, \
										   ACTION_PERM_ALL );
			}
#if 0	/* 11/6/13 Windows sets these flags to what are effectively
				   gibberish values (dataEncipherment for a signing key,
				   digitalSignature for an encryption key) so in order
				   to be able to use the key we have to ignore the keyUsage 
				   settings, in the same way that every other application 
				   seems to */
		if( actionFlags == ACTION_PERM_NONE )
			return( CRYPT_ERROR_NOTAVAIL );
		status = krnlSendMessage( contextInfoPtr->objectHandle, 
								  IMESSAGE_SETATTRIBUTE, &actionFlags, 
								  CRYPT_IATTRIBUTE_ACTIONPERMS );
		if( cryptStatusError( status ) )
			return( status );
#else
		assert( actionFlags != ACTION_PERM_NONE );	/* Warn in debug mode */
#endif /* 0 */
		}
	ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );

	return( CRYPT_OK );
	}