/*----------------------------------------------------------------------- * File: CSM_KEYPARSE.C * * Copyright (c) 1995-2000 Intel Corporation. All rights reserved. *----------------------------------------------------------------------- */ #include "maf_include.h" #include "ber_der.h" #include "csm_keyparse.h" #include "oidsalg.h" /* Local memory allocation functions to be compatible with the BER/DER * library. The BER/DER inteface uses the application memory function * format instead of the local memory function interface, requiring this * conversion. */ static void* CSSMAPI KeyParseMalloc( BER_HANDLE AddInHandle, uint32 Size #ifdef CSSM_MEMTRACK_ON , const char * szFilename, uint32 u32LineNumber #endif ) { return MAF_MALLOC( AddInHandle, Size ); } static void CSSMAPI KeyParseFree( BER_HANDLE AddInHandle, void *MemPtr #ifdef CSSM_MEMTRACK_ON , const char * szFilename, uint32 u32LineNumber #endif ) { MAF_FREE( AddInHandle, MemPtr ); } static void* CSSMAPI KeyParseRealloc( BER_HANDLE AddInHandle, void *MemPtr, uint32 Size #ifdef CSSM_MEMTRACK_ON , const char * szFilename, uint32 u32LineNumber #endif ) { return MAF_REALLOC( AddInHandle, MemPtr, Size ); } static void* CSSMAPI KeyParseCalloc( BER_HANDLE AddInHandle, uint32 Num, uint32 Size #ifdef CSSM_MEMTRACK_ON , const char * szFilename, uint32 u32LineNumber #endif ) { return MAF_CALLOC( AddInHandle, Num, Size ); } static BER_MEMORY_FUNCS KeyParseMemFuncs = { KeyParseMalloc, KeyParseFree, KeyParseRealloc, KeyParseCalloc }; static const unsigned char _BerNullTag[] = { BER_NULL }; static const unsigned char _BerIntegerTag[] = { BER_INTEGER }; static const unsigned char _BerOctetStringTag[] = { BER_OCTET_STRING }; static const unsigned char _BerObjectIdTag[] = { BER_OBJECT_IDENTIFIER }; static const unsigned char _BerConstructedSequenceTag[] = { BER_CONSTRUCTED_SEQUENCE }; uint32 _CSM_GetDERSequenceLength( const BER_PARSED_ITEM *pBerItems, sint32 nNumBerItems ) { uint32 uTotalLength = 0; sint32 i; /* Find length of the individual components */ for ( i = 0; i < nNumBerItems; i++ ) { uTotalLength += pBerItems[i].ContentLength; uTotalLength += BER_LengthOfLength( pBerItems[i].ContentLength ); uTotalLength += BER_LengthOfTag( pBerItems[i].Tag ); } /* Add in length of the sequnce headers */ uTotalLength += BER_LengthOfLength( uTotalLength ); uTotalLength += BER_LengthOfTag( _BerConstructedSequenceTag ); return uTotalLength; } CSSM_RETURN _CSM_AdjustForMSB( const CSSM_DATA *pSrc, CSSM_DATA *pDest ) { int bMsbSet = CSSM_FALSE; assert( pSrc && pDest ); /* Is the MSB set? */ bMsbSet = pSrc->Data[0] & 0x80; /* Allocate a temporary buffer to hold the adjusted data */ pDest->Data = Addin_malloc( pSrc->Length + 1, NULL ); if ( pDest->Data == NULL ) { return CSSMERR_CSP_MEMORY_ERROR; } /* Copy the data using the appropriate method */ if ( bMsbSet ) { /* Add a leading zero so that the unsigned integer remains that way */ pDest->Data[0] = 0x00; memcpy( &pDest->Data[1], pSrc->Data, pSrc->Length ); pDest->Length = pSrc->Length + 1; } else { /* Do a straight copy of the data */ memcpy( pDest->Data, pSrc->Data, pSrc->Length ); pDest->Length = pSrc->Length; } return CSSM_OK; } CSSM_RETURN _CSM_CreateSymmetricKeyblob( CSSM_MODULE_HANDLE ModuleHandle, uint32 KeyFormat, const CSSM_DATA *pKeyParts, uint32 uNumKeyParts, CSSM_DATA *pKeyBlob, CSSM_BOOL *pbAllocated ) { CSSM_RETURN rv; assert( pKeyParts && pKeyBlob && ( uNumKeyParts == 1 ) ); switch ( KeyFormat ) { case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING: { /* Make sure there is enough memory to hold the key */ rv = MAF_CreateOutputBuffer( ModuleHandle, pKeyParts[0].Length, pKeyBlob, pbAllocated ); if ( rv != CSSM_OK ) { return rv; } /* Copy the key material verbatum */ memcpy( pKeyBlob->Data, pKeyParts[0].Data, pKeyParts[0].Length ); pKeyBlob->Length = pKeyParts[0].Length; break; } default: { return CSSMERR_CSP_UNSUPPORTED_KEY_FORMAT; } } return rv; } CSSM_RETURN _CSM_CreateRSAPublicKeyblob( CSSM_MODULE_HANDLE ModuleHandle, uint32 KeyFormat, const CSSM_DATA *pKeyParts, uint32 uNumKeyParts, CSSM_DATA *pKeyBlob, CSSM_BOOL *pbAllocated ) { CSSM_RETURN rv = CSSM_OK; CSSM_DATA TempData; uint32 uRequiredLen; /* Variables required for BER encoding */ BER_PARSED_ITEM BerData[CSM_NUMBER_RSA_PUBLIC_KEY_PARTS]; sint32 i, j; assert( pKeyParts && pKeyBlob && ( uNumKeyParts == CSM_NUMBER_RSA_PUBLIC_KEY_PARTS ) ); /* Determine how the key should be encoded */ switch ( KeyFormat ) { case CSSM_KEYBLOB_RAW_FORMAT_PKCS1: { /* Clear the BER structure */ memset( BerData, 0, sizeof(BerData) ); /* Set the tag types */ for ( i = 0; i < CSM_NUMBER_RSA_PUBLIC_KEY_PARTS; i++ ) { BerData[i].Tag = _BerIntegerTag; /* Make sure the integers have the correct formatting */ rv = _CSM_AdjustForMSB( &pKeyParts[i], &TempData ); if ( rv != CSSM_OK ) { goto bailout_pkcs1; } BerData[i].Content = TempData.Data; BerData[i].ContentLength = TempData.Length; } /* Fetch the output length and allocate output buffer */ /* We don't use the built-in BER/DER library functions since it * allocates memory unconditionally. */ uRequiredLen = _CSM_GetDERSequenceLength( BerData, CSM_NUMBER_RSA_PUBLIC_KEY_PARTS ); rv = MAF_CreateOutputBuffer( ModuleHandle, uRequiredLen, pKeyBlob, pbAllocated ); if ( rv != CSSM_OK ) { goto bailout_pkcs1; } /* Encode the data */ pKeyBlob->Length = DER_ConstructItem( _BerConstructedSequenceTag, CSM_NUMBER_RSA_PUBLIC_KEY_PARTS, BerData, pKeyBlob->Data ); bailout_pkcs1: /* Clean up the temporary buffers we allocated */ for ( j = 0; j < i; j++ ) { Addin_free( (void*)BerData[j].Content, NULL ); } break; } default: { return CSSMERR_CSP_UNSUPPORTED_KEY_FORMAT; } } return rv; } CSSM_RETURN _CSM_CreateRSAPrivateKeyblob( CSSM_MODULE_HANDLE ModuleHandle, uint32 KeyFormat, const CSSM_DATA *pKeyParts, uint32 uNumKeyParts, CSSM_DATA *pKeyBlob, CSSM_BOOL *pbAllocated ) { CSSM_RETURN rv = CSSM_OK; CSSM_DATA TempData; uint32 uRequiredLen; /* Variables required for BER encoding */ BER_PARSED_ITEM BerData[CSM_NUMBER_RSA_PRIVATE_KEY_PARTS]; sint32 i, j; assert( pKeyParts && pKeyBlob && ( uNumKeyParts == CSM_NUMBER_RSA_PRIVATE_KEY_PARTS ) ); /* Clear the BER structure */ memset( BerData, 0, sizeof(BerData) ); /* Set the tag types */ for ( i = 0; i < CSM_NUMBER_RSA_PRIVATE_KEY_PARTS; i++ ) { BerData[i].Tag = _BerIntegerTag; /* Make sure the integers have the correct formatting */ rv = _CSM_AdjustForMSB( &pKeyParts[i], &TempData ); if ( rv != CSSM_OK ) { break; } BerData[i].Content = TempData.Data; BerData[i].ContentLength = TempData.Length; } if ( rv == CSSM_OK ) { /* Determine how the key should be encoded */ switch ( KeyFormat ) { case CSSM_KEYBLOB_RAW_FORMAT_PKCS1: { DER_NODE_PTR RSAPrivateKey = NULL; RSAPrivateKey = DER_AllocateNode( ModuleHandle, &KeyParseMemFuncs, 9 ); if ( RSAPrivateKey != NULL ) { RSAPrivateKey->Tag = _BerConstructedSequenceTag; RSAPrivateKey->Child[0].IsLeaf = CSSM_TRUE; RSAPrivateKey->Child[0].X.Input.Tag = _BerIntegerTag; RSAPrivateKey->Child[0].X.Input.Content = (uint8*)"\0"; RSAPrivateKey->Child[0].X.Input.ContentLength = 1; for ( i = 0; i < CSM_NUMBER_RSA_PRIVATE_KEY_PARTS; i++ ) { RSAPrivateKey->Child[i + 1].IsLeaf = CSSM_TRUE; RSAPrivateKey->Child[i + 1].X.Input = BerData[i]; } /* Fetch the encoded blob length */ uRequiredLen = DER_SizeofTree( RSAPrivateKey ); if ( ( rv = MAF_CreateOutputBuffer( ModuleHandle, uRequiredLen, pKeyBlob, pbAllocated ) ) == CSSM_OK ) { pKeyBlob->Length = DER_CopyTree( RSAPrivateKey, pKeyBlob->Data ); } /* Free the constructed DER tree */ DER_RecycleTree( ModuleHandle, &KeyParseMemFuncs, RSAPrivateKey ); } break; } case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: { DER_NODE_PTR PrivateKeyInfo = NULL; DER_NODE_PTR AlgorithmIdentifier = NULL; DER_NODE_PTR RSAPrivateKey = NULL; /* Construct the BER encoding structure */ /* PrivateKeyInfo */ PrivateKeyInfo = DER_AllocateNode( ModuleHandle, &KeyParseMemFuncs, 3 ); if ( PrivateKeyInfo != NULL ) { PrivateKeyInfo->Tag = _BerConstructedSequenceTag; /* PrivateKeyInfo.version */ PrivateKeyInfo->Child[0].IsLeaf = CSSM_TRUE; PrivateKeyInfo->Child[0].X.Input.Tag = _BerIntegerTag; PrivateKeyInfo->Child[0].X.Input.Content = (uint8*)"\0"; PrivateKeyInfo->Child[0].X.Input.ContentLength = 1; /* PrivateKeyInfo.privateKeyAlgorithm */ PrivateKeyInfo->Child[1].IsLeaf = CSSM_FALSE; PrivateKeyInfo->Child[1].X.Node = DER_AllocateNode( ModuleHandle, &KeyParseMemFuncs, 2 ); AlgorithmIdentifier = PrivateKeyInfo->Child[1].X.Node; if ( AlgorithmIdentifier != NULL ) { AlgorithmIdentifier->Tag = _BerConstructedSequenceTag; /* PrivateKeyInfo.privateKeyAlgorithm.objectId */ AlgorithmIdentifier->Child[0].IsLeaf = CSSM_TRUE; AlgorithmIdentifier->Child[0].X.Input.Tag = _BerObjectIdTag; AlgorithmIdentifier->Child[0].X.Input.Content = OID_RSAEncryption; AlgorithmIdentifier->Child[0].X.Input.ContentLength = sizeof(OID_RSAEncryption); /* PrivateKeyInfo.privateKeyAlgorithm.params */ AlgorithmIdentifier->Child[1].IsLeaf = CSSM_TRUE; AlgorithmIdentifier->Child[1].X.Input.Tag = _BerNullTag; AlgorithmIdentifier->Child[1].X.Input.Content = NULL; AlgorithmIdentifier->Child[1].X.Input.ContentLength = 0; } /* PrivateKeyInfo.privateKey */ /* Fake out the encoder by embedding a RSAPrivateKey inside * of an OCTET STRING type, and not marking the OCTET * STRING as a leaf node in the PrivateKeyInfo structure. */ PrivateKeyInfo->Child[2].IsLeaf = CSSM_FALSE; PrivateKeyInfo->Child[2].X.Node = DER_AllocateNode( ModuleHandle, &KeyParseMemFuncs, 1 ); RSAPrivateKey = PrivateKeyInfo->Child[2].X.Node; if ( RSAPrivateKey != NULL ) { RSAPrivateKey->Tag = _BerOctetStringTag; RSAPrivateKey->Child[0].IsLeaf = CSSM_FALSE; RSAPrivateKey->Child[0].X.Node = DER_AllocateNode( ModuleHandle, &KeyParseMemFuncs, 9 ); RSAPrivateKey = RSAPrivateKey->Child[0].X.Node; if ( RSAPrivateKey != NULL ) { RSAPrivateKey->Tag = _BerConstructedSequenceTag; RSAPrivateKey->Child[0].IsLeaf = CSSM_TRUE; RSAPrivateKey->Child[0].X.Input.Tag = _BerIntegerTag; RSAPrivateKey->Child[0].X.Input.Content = (uint8*)"\0"; RSAPrivateKey->Child[0].X.Input.ContentLength = 1; for ( i = 0; i < CSM_NUMBER_RSA_PRIVATE_KEY_PARTS; i++ ) { RSAPrivateKey->Child[i + 1].IsLeaf = CSSM_TRUE; RSAPrivateKey->Child[i + 1].X.Input = BerData[i]; } } } } /* Make sure the structure was fully constructed */ if ( !RSAPrivateKey || !AlgorithmIdentifier || !PrivateKeyInfo ) { ERR( rv = CSSMERR_CSP_MEMORY_ERROR ); } else { /* Fetch the encoded blob length */ uRequiredLen = DER_SizeofTree( PrivateKeyInfo ); if ( ( rv = MAF_CreateOutputBuffer( ModuleHandle, uRequiredLen, pKeyBlob, pbAllocated ) ) == CSSM_OK ) { pKeyBlob->Length = DER_CopyTree( PrivateKeyInfo, pKeyBlob->Data ); } } /* Free the constructed DER tree (full or partial) */ if ( PrivateKeyInfo != NULL ) { DER_RecycleTree( ModuleHandle, &KeyParseMemFuncs, PrivateKeyInfo ); } break; } default: { ERR( rv = CSSMERR_CSP_UNSUPPORTED_KEY_FORMAT ); } } } /* Clean up the temporary buffers we allocated */ for ( j = 0; j < i; j++ ) { Addin_free( (void*)BerData[j].Content, NULL ); } return rv; } CSSM_RETURN _CSM_CreateDSAPublicKeyblob( CSSM_MODULE_HANDLE ModuleHandle, uint32 KeyFormat, const CSSM_DATA *pKeyParts, uint32 uNumKeyParts, CSSM_DATA *pKeyBlob, CSSM_BOOL *pbAllocated ) { CSSM_RETURN rv = CSSM_OK; CSSM_DATA TempData; uint32 uRequiredLen; /* Variables required for BER encoding */ BER_PARSED_ITEM BerData[CSM_NUMBER_DSA_PUBLIC_KEY_PARTS]; sint32 i, j; assert( pKeyParts && pKeyBlob && ( uNumKeyParts == CSM_NUMBER_DSA_PUBLIC_KEY_PARTS ) ); switch ( KeyFormat ) { case CSSM_KEYBLOB_RAW_FORMAT_FIPS186: { memset( BerData, 0, sizeof(BerData) ); for ( i = 0; i < CSM_NUMBER_DSA_PUBLIC_KEY_PARTS; i++ ) { BerData[i].Tag = _BerIntegerTag; /* Make sure the integers have the correct formatting */ rv = _CSM_AdjustForMSB( &pKeyParts[i], &TempData ); if ( rv != CSSM_OK ) { goto bailout_fips186; } BerData[i].Content = TempData.Data; BerData[i].ContentLength = TempData.Length; } /* Fetch the output length and allocate output buffer */ /* We don't use the built-in BER/DER library functions since it * allocates memory unconditionally. */ uRequiredLen = _CSM_GetDERSequenceLength( BerData, CSM_NUMBER_DSA_PUBLIC_KEY_PARTS ); rv = MAF_CreateOutputBuffer( ModuleHandle, uRequiredLen, pKeyBlob, pbAllocated ); if ( rv != CSSM_OK ) { goto bailout_fips186; } /* Encode the data */ pKeyBlob->Length = DER_ConstructItem( _BerConstructedSequenceTag, CSM_NUMBER_DSA_PUBLIC_KEY_PARTS, BerData, pKeyBlob->Data ); bailout_fips186: /* Clean up the temporary buffers we allocated */ for ( j = 0; j < i; j++ ) { Addin_free( (void*)BerData[j].Content, NULL ); } break; } default: { return CSSMERR_CSP_UNSUPPORTED_KEY_FORMAT; } } return CSSM_OK; } CSSM_RETURN _CSM_CreateDSAPrivateKeyblob( CSSM_MODULE_HANDLE ModuleHandle, uint32 KeyFormat, const CSSM_DATA *pKeyParts, uint32 uNumKeyParts, CSSM_DATA *pKeyBlob, CSSM_BOOL *pbAllocated ) { CSSM_RETURN rv = CSSM_OK; CSSM_DATA TempData; uint32 uRequiredLen; /* Variables required for BER encoding */ BER_PARSED_ITEM BerData[CSM_NUMBER_DSA_PRIVATE_KEY_PARTS]; sint32 i, j; assert( pKeyParts && pKeyBlob && ( uNumKeyParts == CSM_NUMBER_DSA_PRIVATE_KEY_PARTS ) ); /* Reformat the integer components in case the MSB is 1 */ memset( BerData, 0, sizeof(BerData) ); for ( i = 0; i < CSM_NUMBER_DSA_PRIVATE_KEY_PARTS; i++ ) { BerData[i].Tag = _BerIntegerTag; /* Make sure the integers have the correct formatting */ if ( ( rv = _CSM_AdjustForMSB( &pKeyParts[i], &TempData ) ) != CSSM_OK ) { break; } BerData[i].Content = TempData.Data; BerData[i].ContentLength = TempData.Length; } if ( rv == CSSM_OK ) { switch ( KeyFormat ) { case CSSM_KEYBLOB_RAW_FORMAT_FIPS186: { /* Fetch the output length and allocate output buffer */ /* We don't use the built-in BER/DER library functions since it * allocates memory unconditionally. */ uRequiredLen = _CSM_GetDERSequenceLength( BerData, CSM_NUMBER_DSA_PRIVATE_KEY_PARTS ); if ( ( rv = MAF_CreateOutputBuffer( ModuleHandle, uRequiredLen, pKeyBlob, pbAllocated ) ) == CSSM_OK ) { /* Encode the data */ pKeyBlob->Length = DER_ConstructItem( _BerConstructedSequenceTag, CSM_NUMBER_DSA_PRIVATE_KEY_PARTS, BerData, pKeyBlob->Data ); } break; } case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: { DER_NODE_PTR PrivateKeyInfo = NULL; DER_NODE_PTR AlgorithmIdentifier = NULL; DER_NODE_PTR DSAParameters = NULL; DER_NODE_PTR DSAPrivateKey = NULL; /* Construct the BER encoding structure */ /* PrivateKeyInfo */ PrivateKeyInfo = DER_AllocateNode( ModuleHandle, &KeyParseMemFuncs, 3 ); if ( PrivateKeyInfo != NULL ) { PrivateKeyInfo->Tag = _BerConstructedSequenceTag; /* PrivateKeyInfo.version */ PrivateKeyInfo->Child[0].IsLeaf = CSSM_TRUE; PrivateKeyInfo->Child[0].X.Input.Tag = _BerIntegerTag; PrivateKeyInfo->Child[0].X.Input.Content = (uint8*)"\0"; PrivateKeyInfo->Child[0].X.Input.ContentLength = 1; /* PrivateKeyInfo.privateKeyAlgorithm */ PrivateKeyInfo->Child[1].IsLeaf = CSSM_FALSE; PrivateKeyInfo->Child[1].X.Node = DER_AllocateNode( ModuleHandle, &KeyParseMemFuncs, 2 ); AlgorithmIdentifier = PrivateKeyInfo->Child[1].X.Node; if ( AlgorithmIdentifier != NULL ) { AlgorithmIdentifier->Tag = _BerConstructedSequenceTag; /* PrivateKeyInfo.privateKeyAlgorithm.objectId */ /* This may use an old OID value! New X9.57 may exist! */ AlgorithmIdentifier->Child[0].IsLeaf = CSSM_TRUE; AlgorithmIdentifier->Child[0].X.Input.Tag = _BerObjectIdTag; AlgorithmIdentifier->Child[0].X.Input.Content = OID_OIW_DSA; AlgorithmIdentifier->Child[0].X.Input.ContentLength = sizeof(OID_OIW_DSA); /* PrivateKeyInfo.privateKeyAlgorithm.params */ AlgorithmIdentifier->Child[1].IsLeaf = CSSM_FALSE; AlgorithmIdentifier->Child[1].X.Node = DER_AllocateNode( ModuleHandle, &KeyParseMemFuncs, 3 ); DSAParameters = AlgorithmIdentifier->Child[1].X.Node; if ( DSAParameters != NULL ) { DSAParameters->Tag = _BerConstructedSequenceTag; /* PrivateKeyInfo.privateKeyAlgorithm.params.p */ DSAParameters->Child[0].IsLeaf = CSSM_TRUE; DSAParameters->Child[0].X.Input = BerData[CSM_DSA_PRIME]; /* PrivateKeyInfo.privateKeyAlgorithm.params.q */ DSAParameters->Child[1].IsLeaf = CSSM_TRUE; DSAParameters->Child[1].X.Input = BerData[CSM_DSA_SUB_PRIME]; /* PrivateKeyInfo.privateKeyAlgorithm.params.g */ DSAParameters->Child[2].IsLeaf = CSSM_TRUE; DSAParameters->Child[2].X.Input = BerData[CSM_DSA_BASE]; } } /* PrivateKeyInfo.privateKey */ /* Fake out the encoder by embedding an INTEGER inside * of an OCTET STRING type, and not marking the OCTET * STRING as a leaf node in the PrivateKeyInfo structure. */ PrivateKeyInfo->Child[2].IsLeaf = CSSM_FALSE; PrivateKeyInfo->Child[2].X.Node = DER_AllocateNode( ModuleHandle, &KeyParseMemFuncs, 1 ); DSAPrivateKey = PrivateKeyInfo->Child[2].X.Node; if ( DSAPrivateKey != NULL ) { DSAPrivateKey->Tag = _BerOctetStringTag; DSAPrivateKey->Child[0].IsLeaf = CSSM_TRUE; DSAPrivateKey->Child[0].X.Input = BerData[CSM_DSA_PRIVATE_VALUE]; } } /* Make sure the structure was fully constructed */ if ( !DSAPrivateKey || !DSAParameters || !AlgorithmIdentifier || !PrivateKeyInfo ) { ERR( rv = CSSMERR_CSP_MEMORY_ERROR ); } else { /* Fetch the encoded blob length */ uRequiredLen = DER_SizeofTree( PrivateKeyInfo ); if ( ( rv = MAF_CreateOutputBuffer( ModuleHandle, uRequiredLen, pKeyBlob, pbAllocated ) ) == CSSM_OK ) { pKeyBlob->Length = DER_CopyTree( PrivateKeyInfo, pKeyBlob->Data ); } } /* Free the constructed DER tree (full or partial) */ if ( PrivateKeyInfo != NULL ) { DER_RecycleTree( ModuleHandle, &KeyParseMemFuncs, PrivateKeyInfo ); } break; } default: { ERR( rv = CSSMERR_CSP_UNSUPPORTED_KEY_FORMAT ); } } /* switch */ } /* rv == CSSM_OK */ /* Clean up the temporary buffers we allocated */ for ( j = 0; j < i; j++ ) { if ( BerData[j].Content ) { Addin_free( (void*)BerData[j].Content, NULL ); } } return rv; } CSSM_RETURN _CSM_CreateDHPublicKeyblob( CSSM_MODULE_HANDLE ModuleHandle, uint32 KeyFormat, const CSSM_DATA *pKeyParts, uint32 uNumKeyParts, CSSM_DATA *pKeyBlob, CSSM_BOOL *pbAllocated ) { CSSM_RETURN rv = CSSM_OK; assert( pKeyParts && pKeyBlob && ( uNumKeyParts == CSM_NUMBER_DH_PUBLIC_KEY_PARTS ) ); switch ( KeyFormat ) { case CSSM_KEYBLOB_RAW_FORMAT_PKCS3: { /* Allocate the memory for the public key blob */ rv = MAF_CreateOutputBuffer( ModuleHandle, pKeyParts[0].Length, pKeyBlob, pbAllocated ); if ( rv != CSSM_OK ) { return rv; } /* Copy the public value */ memcpy( pKeyBlob->Data, pKeyParts[0].Data, pKeyParts[0].Length ); pKeyBlob->Length = pKeyParts[0].Length; break; } default: { return CSSMERR_CSP_UNSUPPORTED_KEY_FORMAT; } } return CSSM_OK; } CSSM_RETURN CSM_CreateKeyblob( CSSM_MODULE_HANDLE ModuleHandle, CSSM_ALGORITHMS KeyAlgorithm, uint32 KeyClass, uint32 KeyFormat, const CSSM_DATA *pKeyData, uint32 uNumKeyData, CSSM_DATA *pKeyBlob, CSSM_BOOL *pbAllocated ) { assert( pKeyData && pKeyBlob ); switch ( KeyAlgorithm ) { case CSSM_ALGID_RSA: { switch ( KeyClass ) { case CSSM_KEYCLASS_PUBLIC_KEY: { return _CSM_CreateRSAPublicKeyblob( ModuleHandle, KeyFormat, pKeyData, uNumKeyData, pKeyBlob, pbAllocated ); break; } case CSSM_KEYCLASS_PRIVATE_KEY: { return _CSM_CreateRSAPrivateKeyblob( ModuleHandle, KeyFormat, pKeyData, uNumKeyData, pKeyBlob, pbAllocated ); break; } default: { return CSSMERR_CSP_INTERNAL_ERROR; } } break; } case CSSM_ALGID_DSA: { switch ( KeyClass ) { case CSSM_KEYCLASS_PUBLIC_KEY: { return _CSM_CreateDSAPublicKeyblob( ModuleHandle, KeyFormat, pKeyData, uNumKeyData, pKeyBlob, pbAllocated ); break; } case CSSM_KEYCLASS_PRIVATE_KEY: { return _CSM_CreateDSAPrivateKeyblob( ModuleHandle, KeyFormat, pKeyData, uNumKeyData, pKeyBlob, pbAllocated ); break; } default: { return CSSMERR_CSP_INTERNAL_ERROR; } } break; } case CSSM_ALGID_DH: { switch ( KeyClass ) { case CSSM_KEYCLASS_PUBLIC_KEY: { return _CSM_CreateDHPublicKeyblob( ModuleHandle, KeyFormat, pKeyData, uNumKeyData, pKeyBlob, pbAllocated ); break; } case CSSM_KEYCLASS_PRIVATE_KEY: { return CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED; break; } default: { return CSSMERR_CSP_INTERNAL_ERROR; } } break; } default: { if ( KeyClass != CSSM_KEYCLASS_SESSION_KEY ) { return CSSMERR_CSP_UNSUPPORTED_KEY_FORMAT; } return _CSM_CreateSymmetricKeyblob( ModuleHandle, KeyFormat, pKeyData, uNumKeyData, pKeyBlob, pbAllocated ); break; } } return CSSM_OK; } CSSM_RETURN _CSM_ParseSymmetricKeyblob( uint32 KeyFormat, CSSM_DATA *pKeyParts, uint32 *puNumKeyParts, const CSSM_DATA *pKeyBlob ) { CSSM_RETURN rv = CSSM_OK; assert( pKeyParts && pKeyBlob && ( *puNumKeyParts >= 1 ) ); switch ( KeyFormat ) { case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING: { pKeyParts[0] = *pKeyBlob; break; } default: { return CSSMERR_CSP_INVALID_KEY_FORMAT; } } /* Set the output count */ *puNumKeyParts = 1; return rv; } CSSM_RETURN _CSM_ParseRSAPublicKeyblob( uint32 KeyFormat, CSSM_DATA *pKeyParts, uint32 *puNumKeyParts, const CSSM_DATA *pKeyBlob ) { const uint8 *pKeyData = NULL; uint32 uKeyDataLength; BER_PARSED_ITEM BerData[CSM_NUMBER_RSA_PUBLIC_KEY_PARTS]; sint32 SetItemCount; sint32 i; assert( pKeyParts && puNumKeyParts && pKeyBlob ); pKeyData = pKeyBlob->Data; uKeyDataLength = pKeyBlob->Length; switch ( KeyFormat ) { case CSSM_KEYBLOB_RAW_FORMAT_PKCS1: { /* Make sure enough input buffers were passed */ if ( *puNumKeyParts < CSM_NUMBER_RSA_PUBLIC_KEY_PARTS ) { return CSSMERR_CSP_INVALID_DATA_COUNT; } *puNumKeyParts = CSM_NUMBER_RSA_PUBLIC_KEY_PARTS; /* Parse the key data */ pKeyData = BER_ExpandItem( pKeyData, uKeyDataLength, BerData ); if ( ( pKeyData != NULL ) && ( *BerData[0].Tag == BER_CONSTRUCTED_SEQUENCE ) ) { SetItemCount = BER_ExpandSet( BerData[0].Content, BerData[0].ContentLength, CSM_NUMBER_RSA_PUBLIC_KEY_PARTS, 0, NULL, BerData ); if ( SetItemCount == CSM_NUMBER_RSA_PUBLIC_KEY_PARTS ) { for ( i = 0; i < SetItemCount; i++ ) { /* Make sure all parts of the key are integers */ if ( *BerData[i].Tag != BER_INTEGER ) { return CSSMERR_CSP_INVALID_KEY; } /* Strip the leading zero from the front */ if ( BerData[i].Content[0] == 0x00 ) { BerData[i].Content++; BerData[i].ContentLength--; } pKeyParts[i].Data = (uint8*)BerData[i].Content; pKeyParts[i].Length = BerData[i].ContentLength; } } else { return CSSMERR_CSP_INVALID_KEY; } /* correct number of items */ } else { return CSSMERR_CSP_INVALID_KEY; } /* Is a constructed sequence */ break; } default: { return (CSSMERR_CSP_UNSUPPORTED_KEY_FORMAT); } } return CSSM_OK; } #define _IsBadPKCS8PrivateKeyInfo( pki ) \ ( ( *(pki)->Tag != BER_CONSTRUCTED_SEQUENCE ) || \ ( (pki)->Count != 3 ) || \ /* PrivateKeyInfo.version */ \ ( !(pki)->Child[0].IsLeaf ) || \ ( *(pki)->Child[0].X.Input.Tag != BER_INTEGER ) || \ ( (pki)->Child[0].X.Input.ContentLength != 1 ) || \ ( (pki)->Child[0].X.Input.Content[0] != '\0' ) || \ /* PrivateKeyInfo.privateKeyAlgorithm */ \ ( (pki)->Child[1].IsLeaf ) || \ ( (pki)->Child[1].X.Node == NULL ) || \ /* PrivateKeyInfo.privateKey */ \ ( !(pki)->Child[2].IsLeaf ) || \ ( *(pki)->Child[2].X.Input.Tag != BER_OCTET_STRING ) \ ) #define _IsBadNoParamAlgorithmIdentifier( aid, oid ) \ ( ( *(aid)->Tag != BER_CONSTRUCTED_SEQUENCE ) || \ ( (aid)->Count != 2 ) || \ /* AlgorithmIdentifier.algOid */ \ ( !(aid)->Child[0].IsLeaf ) || \ ( *(aid)->Child[0].X.Input.Tag != BER_OBJECT_IDENTIFIER ) || \ ( (aid)->Child[0].X.Input.ContentLength != sizeof(oid) ) || \ ( memcmp( (aid)->Child[0].X.Input.Content, (oid), sizeof(oid) ) ) || \ /* AlgorithmIdentifier.params */ \ ( !(aid)->Child[1].IsLeaf ) || \ ( *((aid)->Child[1].X.Input.Tag) != BER_NULL ) \ ) #define _IsBadDSAAlgorithmIdentifier( aid, oid ) \ ( ( *(aid)->Tag != BER_CONSTRUCTED_SEQUENCE ) || \ ( (aid)->Count != 2 ) || \ /* AlgorithmIdentifier.algOid */ \ ( !(aid)->Child[0].IsLeaf ) || \ ( *(aid)->Child[0].X.Input.Tag != BER_OBJECT_IDENTIFIER ) || \ ( (aid)->Child[0].X.Input.ContentLength != sizeof(oid) ) || \ ( memcmp( (aid)->Child[0].X.Input.Content, (oid), sizeof(oid) ) ) || \ /* AlgorithmIdentifier.params */ \ ( (aid)->Child[1].IsLeaf ) || \ ( (aid)->Child[1].X.Node == NULL ) \ ) CSSM_RETURN _CSM_ParseRSAPrivateKeyblob( uint32 KeyFormat, CSSM_DATA *pKeyParts, uint32 *puNumKeyParts, const CSSM_DATA *pKeyBlob ) { CSSM_RETURN rv = CSSM_OK; const uint8 *pKeyData = NULL; uint32 uKeyDataLength; BER_PARSED_ITEM BerData[CSM_NUMBER_RSA_PRIVATE_KEY_PARTS + 1]; sint32 SetItemCount; sint32 i; assert( pKeyParts && puNumKeyParts && pKeyBlob ); pKeyData = pKeyBlob->Data; uKeyDataLength = pKeyBlob->Length; /* Make sure enough input buffers were passed */ if ( *puNumKeyParts < CSM_NUMBER_RSA_PRIVATE_KEY_PARTS ) { ERR( rv = CSSMERR_CSP_INVALID_DATA_COUNT ); } else { *puNumKeyParts = CSM_NUMBER_RSA_PRIVATE_KEY_PARTS; switch ( KeyFormat ) { case CSSM_KEYBLOB_RAW_FORMAT_PKCS1: { /* Parse the key data */ pKeyData = BER_ExpandItem( pKeyData, uKeyDataLength, BerData ); if ( ( pKeyData != NULL ) && ( *BerData[0].Tag == BER_CONSTRUCTED_SEQUENCE ) ) { SetItemCount = BER_ExpandSet( BerData[0].Content, BerData[0].ContentLength, CSM_NUMBER_RSA_PRIVATE_KEY_PARTS + 1, 0, NULL, BerData ); if ( SetItemCount == ( CSM_NUMBER_RSA_PRIVATE_KEY_PARTS + 1 ) ) { /* Check the version number */ if ( ( *BerData[0].Tag != BER_INTEGER ) || ( BerData[0].ContentLength != 1 ) || ( BerData[0].Content[0] != '\0' ) ) { ERR( rv = CSSMERR_CSP_INVALID_KEY ); } else { for ( i = 1; i < SetItemCount; i++ ) { /* Make sure all parts of the key are integers */ if ( *BerData[i].Tag != BER_INTEGER ) { ERR( rv = CSSMERR_CSP_INVALID_KEY ); break; } /* Strip the leading zero from the front */ if ( BerData[i].Content[0] == 0x00 ) { BerData[i].Content++; BerData[i].ContentLength--; } pKeyParts[i - 1].Data = (uint8*)BerData[i].Content; pKeyParts[i - 1].Length = BerData[i].ContentLength; } } /* Check version */ } else { ERR( rv = CSSMERR_CSP_INVALID_KEY ); } /* correct number of items */ } else { ERR( rv = CSSMERR_CSP_INVALID_KEY ); } /* Is a constructed sequence */ break; } case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: { DER_NODE_PTR pPrivateKeyInfo = NULL; DER_NODE_PTR pAlgorithmId = NULL; /* Crack the outer sequence */ pKeyData = BER_ExpandItem( pKeyData, uKeyDataLength, BerData ); if ( ( pKeyData != NULL ) && ( *BerData[0].Tag == BER_CONSTRUCTED_SEQUENCE ) ) { /* Parse the sequence internals */ pPrivateKeyInfo = BER_ParseComplexObject( MAF_ALLOCATE_LOCAL, &KeyParseMemFuncs, NULL, BerData ); if ( pPrivateKeyInfo == NULL ) { ERR( rv = CSSMERR_CSP_INVALID_KEY ); } else { /* Validate the parsed structure */ if ( _IsBadPKCS8PrivateKeyInfo( pPrivateKeyInfo ) || ( ( pAlgorithmId = pPrivateKeyInfo->Child[1].X.Node ) == NULL ) || _IsBadNoParamAlgorithmIdentifier( pAlgorithmId, OID_RSAEncryption ) ) { ERR( rv = CSSMERR_CSP_INVALID_KEY ); } else { pKeyData = pPrivateKeyInfo->Child[2].X.Input.Content; uKeyDataLength = pPrivateKeyInfo->Child[2].X.Input.ContentLength; /* Parse the key data */ pKeyData = BER_ExpandItem( pKeyData, uKeyDataLength, BerData ); if ( ( pKeyData != NULL ) && ( *BerData[0].Tag == BER_CONSTRUCTED_SEQUENCE ) ) { SetItemCount = BER_ExpandSet( BerData[0].Content, BerData[0].ContentLength, CSM_NUMBER_RSA_PRIVATE_KEY_PARTS + 1, 0, NULL, BerData ); if ( SetItemCount == ( CSM_NUMBER_RSA_PRIVATE_KEY_PARTS + 1 ) ) { /* Check the version number */ if ( ( *BerData[0].Tag != BER_INTEGER ) || ( BerData[0].ContentLength != 1 ) || ( BerData[0].Content[0] != '\0' ) ) { ERR( rv = CSSMERR_CSP_INVALID_KEY ); } else { for ( i = 1; i < SetItemCount; i++ ) { /* Make sure all parts of the key are integers */ if ( *BerData[i].Tag != BER_INTEGER ) { ERR( rv = CSSMERR_CSP_INVALID_KEY ); break; } /* Strip the leading zero from the front */ if ( BerData[i].Content[0] == 0x00 ) { BerData[i].Content++; BerData[i].ContentLength--; } pKeyParts[i - 1].Data = (uint8*)BerData[i].Content; pKeyParts[i - 1].Length = BerData[i].ContentLength; } } /* Check version */ } else { ERR( rv = CSSMERR_CSP_INVALID_KEY ); } /* Check for correct item count */ } /* Crack the outer sequence of the key data */ } /* Validate the parse tree */ /* Free the parsed structure */ DER_RecycleTree( MAF_ALLOCATE_LOCAL, &KeyParseMemFuncs, pPrivateKeyInfo ); } /* Parse PrivateKeyInfo */ } else { ERR( rv = CSSMERR_CSP_INVALID_KEY ); } /* Crack outer sequence */ break; } default: { assert( 0 ); ERR( rv = CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED ); } } } return rv; } CSSM_RETURN _CSM_ParseDSAPublicKeyblob( uint32 KeyFormat, CSSM_DATA *pKeyParts, uint32 *puNumKeyParts, const CSSM_DATA *pKeyBlob ) { const uint8 *pKeyData = NULL; uint32 uKeyDataLength; BER_PARSED_ITEM BerData[CSM_NUMBER_DSA_PUBLIC_KEY_PARTS]; sint32 SetItemCount; sint32 i; assert( pKeyParts && puNumKeyParts && pKeyBlob ); pKeyData = pKeyBlob->Data; uKeyDataLength = pKeyBlob->Length; switch ( KeyFormat ) { case CSSM_KEYBLOB_RAW_FORMAT_FIPS186: { /* Make sure enough output buffers were passed */ if ( *puNumKeyParts < CSM_NUMBER_DSA_PUBLIC_KEY_PARTS ) { return CSSMERR_CSP_INVALID_DATA_COUNT; } *puNumKeyParts = CSM_NUMBER_DSA_PUBLIC_KEY_PARTS; /* Parse the key data */ pKeyData = BER_ExpandItem( pKeyData, uKeyDataLength, BerData ); if ( ( pKeyData != NULL) && ( *BerData[0].Tag == BER_CONSTRUCTED_SEQUENCE ) ) { SetItemCount = BER_ExpandSet( BerData[0].Content, BerData[0].ContentLength, CSM_NUMBER_DSA_PUBLIC_KEY_PARTS, 0, NULL, BerData ); if ( SetItemCount != CSM_NUMBER_DSA_PUBLIC_KEY_PARTS ) { return CSSMERR_CSP_INVALID_KEY; } else { for ( i = 0; i < SetItemCount; i++ ) { if ( *BerData[i].Tag != BER_INTEGER ) { return CSSMERR_CSP_INVALID_KEY; } if ( BerData[i].Content[0] == 0x00 ) { BerData[i].Content++; BerData[i].ContentLength--; } pKeyParts[i].Data = (uint8*)BerData[i].Content; pKeyParts[i].Length = BerData[i].ContentLength; } } } else { return CSSMERR_CSP_INVALID_KEY; } break; } default: { return CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED; break; } } return CSSM_OK; } #define _IsBadDSAParams( params ) \ ( ( *(params)->Tag != BER_CONSTRUCTED_SEQUENCE ) || \ ( (params)->Count != 3 ) || \ /* DSAParams.p */ \ ( !(params)->Child[0].IsLeaf ) || \ ( *(params)->Child[0].X.Input.Tag != BER_INTEGER ) || \ /* DSAParams.q */ \ ( !(params)->Child[1].IsLeaf ) || \ ( *(params)->Child[1].X.Input.Tag != BER_INTEGER ) || \ /* DSAParams.g */ \ ( !(params)->Child[2].IsLeaf ) || \ ( *(params)->Child[2].X.Input.Tag != BER_INTEGER ) \ ) CSSM_RETURN _CSM_ParseDSAPrivateKeyblob( uint32 KeyFormat, CSSM_DATA *pKeyParts, uint32 *puNumKeyParts, const CSSM_DATA *pKeyBlob ) { CSSM_RETURN rv = CSSM_OK; const uint8 *pKeyData = NULL; uint32 uKeyDataLength; BER_PARSED_ITEM BerData[CSM_NUMBER_DSA_PRIVATE_KEY_PARTS]; sint32 SetItemCount; sint32 i; assert( pKeyParts && puNumKeyParts && pKeyBlob ); pKeyData = pKeyBlob->Data; uKeyDataLength = pKeyBlob->Length; /* Make sure enough output buffers were passed */ if ( *puNumKeyParts < CSM_NUMBER_DSA_PRIVATE_KEY_PARTS ) { ERR( rv = CSSMERR_CSP_INVALID_DATA_COUNT ); } else { *puNumKeyParts = CSM_NUMBER_DSA_PRIVATE_KEY_PARTS; switch ( KeyFormat ) { case CSSM_KEYBLOB_RAW_FORMAT_FIPS186: { /* Parse the key data */ pKeyData = BER_ExpandItem( pKeyData, uKeyDataLength, BerData ); if ( ( pKeyData != NULL) && ( *BerData[0].Tag == BER_CONSTRUCTED_SEQUENCE ) ) { SetItemCount = BER_ExpandSet( BerData[0].Content, BerData[0].ContentLength, CSM_NUMBER_DSA_PRIVATE_KEY_PARTS, 0, NULL, BerData ); if ( SetItemCount != CSM_NUMBER_DSA_PRIVATE_KEY_PARTS ) { ERR( rv = CSSMERR_CSP_INVALID_KEY ); } else { for ( i = 0; i < SetItemCount; i++ ) { if ( *BerData[i].Tag != BER_INTEGER ) { ERR( rv = CSSMERR_CSP_INVALID_KEY ); break; } if ( BerData[i].Content[0] == 0x00 ) { BerData[i].Content++; BerData[i].ContentLength--; } pKeyParts[i].Data = (uint8*)BerData[i].Content; pKeyParts[i].Length = BerData[i].ContentLength; } } } else { ERR( rv = CSSMERR_CSP_INVALID_KEY ); } break; } case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: { DER_NODE_PTR pPrivateKeyInfo = NULL; DER_NODE_PTR pAlgorithmId = NULL; DER_NODE_PTR pParams = NULL; /* Crack the outer sequence */ pKeyData = BER_ExpandItem( pKeyData, uKeyDataLength, BerData ); if ( ( pKeyData != NULL ) && ( *BerData[0].Tag == BER_CONSTRUCTED_SEQUENCE ) ) { /* Parse the sequence internals */ pPrivateKeyInfo = BER_ParseComplexObject( MAF_ALLOCATE_LOCAL, &KeyParseMemFuncs, NULL, BerData ); if ( pPrivateKeyInfo == NULL ) { ERR( rv = CSSMERR_CSP_INVALID_KEY ); } else { /* Validate the parsed structure */ if ( _IsBadPKCS8PrivateKeyInfo( pPrivateKeyInfo ) || ( ( pAlgorithmId = pPrivateKeyInfo->Child[1].X.Node ) == NULL ) || _IsBadDSAAlgorithmIdentifier( pAlgorithmId, OID_OIW_DSA ) || ( ( pParams = pAlgorithmId->Child[1].X.Node ) == NULL ) || _IsBadDSAParams( pParams ) ) { ERR( rv = CSSMERR_CSP_INVALID_KEY ); } else { /* Parse the key data */ if ( ( BER_ExpandItem( pPrivateKeyInfo->Child[2].X.Input.Content, pPrivateKeyInfo->Child[2].X.Input.ContentLength, BerData ) == NULL ) || ( *BerData[0].Tag != BER_INTEGER ) ) { ERR( rv = CSSMERR_CSP_INVALID_KEY ); } else { /* Pull the key parts out of the parse tree */ pKeyParts[CSM_DSA_PRIME].Data = (uint8*)pParams->Child[0].X.Input.Content; pKeyParts[CSM_DSA_PRIME].Length = pParams->Child[0].X.Input.ContentLength; pKeyParts[CSM_DSA_SUB_PRIME].Data = (uint8*)pParams->Child[1].X.Input.Content; pKeyParts[CSM_DSA_SUB_PRIME].Length = pParams->Child[1].X.Input.ContentLength; pKeyParts[CSM_DSA_BASE].Data = (uint8*)pParams->Child[2].X.Input.Content; pKeyParts[CSM_DSA_BASE].Length = pParams->Child[2].X.Input.ContentLength; pKeyParts[CSM_DSA_PRIVATE_VALUE].Data = (uint8*)BerData[0].Content; pKeyParts[CSM_DSA_PRIVATE_VALUE].Length = BerData[0].ContentLength; /* Adjust the integers to strip the leading zeros */ for ( i = 0; i < CSM_NUMBER_DSA_PRIVATE_KEY_PARTS; i++ ) { if ( pKeyParts[i].Data[0] == 0x00 ) { pKeyParts[i].Data++; pKeyParts[i].Length--; } } } /* Parse the key data octet string */ } /* Validate the parse tree */ /* Free the parsed structure */ DER_RecycleTree( MAF_ALLOCATE_LOCAL, &KeyParseMemFuncs, pPrivateKeyInfo ); } /* Parse PrivateKeyInfo */ } else { ERR( rv = CSSMERR_CSP_INVALID_KEY ); } /* Crack outer sequence */ break; } default: { ERR( rv = CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED ); break; } } /* switch KeyFormat */ } /* Correct number of output buffers passed */ return rv; } CSSM_RETURN _CSM_ParseDHPublicKeyblob( uint32 KeyFormat, CSSM_DATA *pKeyParts, uint32 *puNumKeyParts, const CSSM_DATA *pKeyBlob ) { assert( pKeyParts && puNumKeyParts && pKeyBlob ); switch ( KeyFormat ) { case CSSM_KEYBLOB_RAW_FORMAT_PKCS3: { *puNumKeyParts = 1; pKeyParts[0] = *pKeyBlob; break; } default: { return CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED; break; } } return CSSM_OK; } CSSM_RETURN CSM_ParseKeyblob( CSSM_ALGORITHMS KeyAlgorithm, uint32 KeyClass, uint32 KeyFormat, CSSM_DATA *pKeyData, uint32 *puNumKeyData, const CSSM_DATA *pKeyBlob ) { switch ( KeyAlgorithm ) { case CSSM_ALGID_RSA: { switch ( KeyClass ) { case CSSM_KEYCLASS_PUBLIC_KEY: { return _CSM_ParseRSAPublicKeyblob( KeyFormat, pKeyData, puNumKeyData, pKeyBlob ); break; } case CSSM_KEYCLASS_PRIVATE_KEY: { return _CSM_ParseRSAPrivateKeyblob( KeyFormat, pKeyData, puNumKeyData, pKeyBlob ); break; } default: { assert( 0 ); return CSSMERR_CSP_INVALID_KEY; } } break; } case CSSM_ALGID_DSA: { switch ( KeyClass ) { case CSSM_KEYCLASS_PUBLIC_KEY: { return _CSM_ParseDSAPublicKeyblob( KeyFormat, pKeyData, puNumKeyData, pKeyBlob ); break; } case CSSM_KEYCLASS_PRIVATE_KEY: { return _CSM_ParseDSAPrivateKeyblob( KeyFormat, pKeyData, puNumKeyData, pKeyBlob ); break; } default: { assert( 0 ); return CSSMERR_CSP_INVALID_KEY; } } break; } case CSSM_ALGID_DH: { switch ( KeyClass ) { case CSSM_KEYCLASS_PUBLIC_KEY: { return _CSM_ParseDHPublicKeyblob( KeyFormat, pKeyData, puNumKeyData, pKeyBlob ); break; } case CSSM_KEYCLASS_PRIVATE_KEY: { return CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED; break; } default: { assert( 0 ); return CSSMERR_CSP_INVALID_KEY; } } break; } default: { if ( KeyClass != CSSM_KEYCLASS_SESSION_KEY ) { return CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED; } return _CSM_ParseSymmetricKeyblob( KeyFormat, pKeyData, puNumKeyData, pKeyBlob ); } } return CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED; }