/*----------------------------------------------------------------------- * File: CSM_SESN.C * * Copyright (c) 1995-2000 Intel Corporation. All rights reserved. *----------------------------------------------------------------------- */ /* * OpenVMS History * * 13-Sep-2002 Carol Kelly * o Merge in V3_14 changes * */ #include "maf_include.h" #include "csm_cntx.h" static void MLC_FASTCALL s_CSM_SessionTeardown( void *pItem ) { CSM_SESSION *pSession = (CSM_SESSION*)pItem; CSM_DeleteSession( pSession ); } static int MLC_FASTCALL s_CSM_FindSessionByCCHandle( const CSM_SESSION *pSession, /* void *pItem */ const CSSM_CC_HANDLE *phContext /* void *pKey */ ) { if ( pSession->hContext == (*phContext) ) { return 0; } return -1; } static int MLC_FASTCALL s_CSM_FindSessionByPointer( const CSM_SESSION *pSession, /* void *pItem*/ const CSM_SESSION *pTargetSession /* void *pKey */ ) { if ( pSession == pTargetSession ) { return 0; } return -1; } /**------------------------------------------------------------------------- ** CSM_SessionListInit ** ** Description ** Initializes a CSM_SESSION_LIST structure, The structure is cleared and ** internal locks are created. This function should not be called on the ** same structure twice since there is no way to detect previous ** operations. CSM_SessionListTerminate must be called to counteract the ** effects of this function. ** ** Parameters ** pList (input) - CSM_SESSION_LIST structure to initialize. ** ** Return Values ** CSSM_OK - The structure was successfully initialized. ** MAFR_FAIL - Locks on the structure could not be initialized. *-------------------------------------------------------------------------- **/ CSSM_RETURN CSM_SessionListInit( CSM_SESSION_LIST *pList ) { CSSM_RETURN rv = CSSM_OK; MAF_LIST_COLLECTION *pCLCList = pList; /* Initialize the session list */ rv = MLC_Init( pCLCList, s_CSM_SessionTeardown ); return rv; } /**------------------------------------------------------------------------- ** CSM_SessionListTerminate ** ** Description ** Counteracts the effects of the CSM_SessionListInit function. All ** sessions remaining in the list are deallocated before releasing the ** internal locks. The structure can not be used again until it is ** initialized again. ** ** NOTE: If the function fails, internal locking mechanisms could not be ** released and may result in system resource leaks, including memory. ** This condition should only happen when the system becomes unstable. ** ** Parameters ** pList (input) - CSM_SESSION_LIST structure to terminate. ** ** Return Values ** CSSM_OK - The structure was successfully terminated and all resources ** were released. ** MAFR_FAIL - Not all resources could be successfully released. *-------------------------------------------------------------------------- **/ CSSM_RETURN CSM_SessionListTerminate( CSM_SESSION_LIST *pList ) { CSSM_RETURN rv = CSSM_OK; MAF_LIST_COLLECTION *pCLCList = pList; /* Free the remaining session records and resources*/ rv = MLC_Term( pCLCList ); return rv; } /**------------------------------------------------------------------------- ** CSM_CreateSession ** ** Description ** Creates a CSM_SESSION object independent of a CSM_SESSION_LIST. Memory ** for the structure is allocated on the local heap using Addin_malloc. ** The context structure is duplicated on the local heap for future ** use by the caller. The algorithm state will be cleared and can be ** added to the structure using the CSM_AllocateSessionState function. ** The context attribute pointers will be set to NULL. Use the ** CSM_ExtractContextAttributes function to fill in the values. ** ** Parameters ** CSPHandle (input) - Attach handle that the application used to call the ** API creating the session. ** CCHandle (input) - Crypto context handle that is used to reference the ** CSSM_CONTEXT structure in pContext. ** pContext (input) - Crypto context to associate with the session. The ** structure is duplicated and placed in the session. ** SessionType (input) - One of the CSM_ST_* constants. Indicates to users ** of the session how the context should be used. ** ppNewSession (output) - Pointer to the new session structure. ** ** Return Values ** CSSM_CSP_INVALID_CSP_HANDLE - The CSP handle is CSSM_INVALID_HANDLE. ** CSSMERR_CSP_INVALID_CONTEXT_HANDLE - The CC handle is CSSM_INVALID_HANDLE. ** CSSM_CSP_INVALID_CONTEXT_POINTER - The CSSM_CONTEXT structure ** referenced by pContext is not usable. ** CSSMERR_CSP_MEMORY_ERROR - The complete session structure and context copy ** could not be allocated. ** CSSM_OK - The new session structure has been allocated. *-------------------------------------------------------------------------- **/ CSSM_RETURN CSM_CreateSession( CSSM_CSP_HANDLE CSPHandle, CSSM_CC_HANDLE CCHandle, const CSSM_CONTEXT *pContext, CSM_SESSION_TYPE SessionType, CSM_SESSION **ppNewSession ) { CSSM_RETURN rv = CSSM_OK; CSM_SESSION *pSession = NULL; /* Parameter check */ if ( CCHandle == CSSM_INVALID_HANDLE ) { ERR( rv = CSSMERR_CSP_INVALID_CONTEXT_HANDLE ); } else if ( pContext == NULL ) { ERR( rv = CSSMERR_CSP_INVALID_CONTEXT ); } else { /* Check to make sure the session and context types mesh */ switch ( SessionType ) { case CSM_ST_DIGEST: { if ( pContext->ContextType != CSSM_ALGCLASS_DIGEST ) { ERR( rv = CSSMERR_CSP_INVALID_CONTEXT ); } break; } case CSM_ST_RANDOMGEN: { if ( pContext->ContextType != CSSM_ALGCLASS_RANDOMGEN ) { ERR( rv = CSSMERR_CSP_INVALID_CONTEXT ); } break; } case CSM_ST_UNIQUEGEN: { if ( pContext->ContextType != CSSM_ALGCLASS_UNIQUEGEN ) { ERR( rv = CSSMERR_CSP_INVALID_CONTEXT ); } break; } case CSM_ST_KEYGEN: { if ( pContext->ContextType != CSSM_ALGCLASS_KEYGEN ) { ERR( rv = CSSMERR_CSP_INVALID_CONTEXT ); } break; } case CSM_ST_DERIVE: { if ( pContext->ContextType != CSSM_ALGCLASS_DERIVEKEY ) { ERR( rv = CSSMERR_CSP_INVALID_CONTEXT ); } break; } case CSM_ST_ENCRYPT: case CSM_ST_DECRYPT: case CSM_ST_WRAP: case CSM_ST_UNWRAP: { if ( ( pContext->ContextType != CSSM_ALGCLASS_SYMMETRIC ) && ( pContext->ContextType != CSSM_ALGCLASS_ASYMMETRIC ) ) { ERR( rv = CSSMERR_CSP_INVALID_CONTEXT ); } break; } case CSM_ST_SIGN: case CSM_ST_VERIFY: { if ( pContext->ContextType != CSSM_ALGCLASS_SIGNATURE ) { ERR( rv = CSSMERR_CSP_INVALID_CONTEXT ); } break; } case CSM_ST_GEN_MAC: case CSM_ST_VERIFY_MAC: { if ( pContext->ContextType != CSSM_ALGCLASS_MAC ) { ERR( rv = CSSMERR_CSP_INVALID_CONTEXT ); } break; } case CSM_ST_CUSTOM: { #ifndef CSM_TRUSTWAY /* bypass to allow passthrough operation on any context type */ /* trustway: digest key implementation */ if ( pContext->ContextType != CSSM_ALGCLASS_CUSTOM ) { ERR( rv = CSSMERR_CSP_INVALID_CONTEXT ); } #endif break; } case CSM_ST_NONE: default: { ERR( rv = CSSMERR_CSP_INVALID_CONTEXT ); } } if ( rv == CSSM_OK ) { /* Allocates session structure */ pSession = (CSM_SESSION*)Addin_malloc( sizeof(CSM_SESSION), NULL ); if ( pSession == NULL ) { ERR( rv = CSSMERR_CSP_MEMORY_ERROR ); } else { /* Fill in the structure */ memset( pSession, 0, sizeof(CSM_SESSION) ); #ifdef _DEBUG pSession->__MagicNumber = __CSM_SESSION_MAGIC_NUMBER; #endif pSession->hCsp = CSPHandle; pSession->hContext = CCHandle; pSession->SessionType = SessionType; pSession->uCryptoStateSize = 0; pSession->pCryptoState = NULL; /* duplicate context in the session */ if ( ( rv = CSM_DuplicateContext( pContext, &pSession->pContext ) ) == CSSM_OK ) { *ppNewSession = pSession; } else { memset( pSession, 0, sizeof(CSM_SESSION) ); Addin_free( pSession, NULL ); } /* CSM_DuplicateContext */ } /* Addin_malloc */ } /* Operation and context type match */ } /* Validation */ return rv; } CSSM_RETURN CSM_DeleteSession( CSM_SESSION *pSession ) { CSSM_RETURN rv = CSSM_OK; /* Parameter check */ if ( pSession != NULL ) { ASSERT_VALID_CSM_SESSION( pSession ); /* Deallocate the duplicated context */ if ( pSession->pContext != NULL ) { CSM_FreeContext( pSession->pContext ); } /* Wipe and deallocate any state information */ if ( pSession->pCryptoState != NULL ) { memset( pSession->pCryptoState, 0, pSession->uCryptoStateSize ); Addin_free( pSession->pCryptoState, NULL ); } /* Free the context structure */ Addin_free( pSession, NULL ); } return rv; } CSSM_RETURN CSM_AllocateSessionState( CSM_SESSION *pSession, uint32 uSize ) { CSSM_RETURN rv = CSSM_OK; void *pTempState = NULL; /* Parameter check */ if ( pSession == NULL ) { ERR( rv = CSSMERR_CSP_INTERNAL_ERROR ); } else { ASSERT_VALID_CSM_SESSION( pSession ); /* Allocate the state buffer */ if ( pSession->pCryptoState != NULL ) { pTempState = Addin_realloc( pSession->pCryptoState, uSize, NULL ); } else { pTempState = Addin_malloc( uSize, NULL ); } /* Check that allocation succeded */ if ( pTempState == NULL ) { ERR( rv = CSSMERR_CSP_MEMORY_ERROR ); } else { /* Assign the buffer */ pSession->pCryptoState = pTempState; pSession->uCryptoStateSize = uSize; } } return rv; } CSSM_RETURN CSM_CreateStagedSession( CSM_SESSION_LIST *pList, CSSM_CSP_HANDLE CSPHandle, CSSM_CC_HANDLE CCHandle, const CSSM_CONTEXT *pContext, CSM_SESSION_TYPE SessionType, CSM_SESSION **ppNewSession, MLC_LOCK_REF *pLockRef ) { CSSM_RETURN rv = CSSM_OK; MAF_LIST_COLLECTION *pCLCList = pList; CSM_SESSION *pSession = NULL; MLC_LOCK_REF LockRef; /* See if a staged session already exists with this information */ rv = CSM_FindStagedSession( pCLCList, CCHandle, MLC_NO_LOCK, &pSession, &LockRef ); if ( rv == CSSM_OK ) { ERR( rv = CSSMERR_CSP_STAGED_OPERATION_IN_PROGRESS ); } else if ( rv != CSSMERR_CSP_STAGED_OPERATION_NOT_STARTED ) { ERR( rv = CSSMERR_CSP_INTERNAL_ERROR ); } else { /* Create session structure */ if ( ( rv = CSM_CreateSession( CSPHandle, CCHandle, pContext, SessionType, &pSession ) ) == CSSM_OK ) { /* Add the session to the session list */ if ( ( rv = MLC_AddItem( pCLCList, pSession, MLC_WRITE_LOCK, &LockRef ) ) != CSSM_OK ) { CSM_DeleteSession( pSession ); MAF_OutputDebugString( "Cannot add a session to token manager." ); if ( rv == MLC_ERR_RESOURCE ) { ERR( rv = CSSMERR_CSP_INTERNAL_ERROR ); } } else { /* Return the new session and lock reference */ *ppNewSession = pSession; *pLockRef = LockRef; } /* MLC_AddItem */ } /* CSM_CreateSession */ } /* Validation */ return rv; } CSSM_RETURN CSM_DeleteStagedSession( CSM_SESSION_LIST *pList, CSM_SESSION *pSession ) { CSSM_RETURN rv = CSSM_OK; MAF_LIST_COLLECTION *pCLCList = pList; CSM_SESSION *pDoomedSession = NULL; /* Parameter check */ if ( pSession != NULL ) { ASSERT_VALID_CSM_SESSION( pSession ); /* Unlink the item from the list */ rv = MLC_DeleteItem( pCLCList, (MLC_FIND_FUNC)s_CSM_FindSessionByPointer, pSession, (void**)&pDoomedSession ); if ( rv != CSSM_OK ) { ERR( rv = CSSMERR_CSP_INTERNAL_ERROR ); } else { assert( pDoomedSession == pSession ); /* Delete the session */ CSM_DeleteSession( pDoomedSession ); } } return rv; } CSSM_RETURN CSM_FindStagedSession( const CSM_SESSION_LIST *pList, CSSM_CC_HANDLE CCHandle, MLC_LOCK_TYPE ltLockType, CSM_SESSION **ppFoundSession, MLC_LOCK_REF *ppLockRef ) { CSSM_RETURN rv = CSSM_OK; MAF_LIST_COLLECTION *pCLCList = (MAF_LIST_COLLECTION*)pList; CSM_SESSION *pSession; /* Parameter check */ if ( CCHandle == CSSM_INVALID_HANDLE ) { ERR( rv = CSSMERR_CSP_INVALID_CONTEXT_HANDLE ); } else if ( ( pList == NULL ) || ( ppFoundSession == NULL ) || ( ppLockRef == NULL ) ) { ERR( rv = CSSMERR_CSP_INTERNAL_ERROR ); } else { /* Find the item and return the record pointer. */ rv = MLC_FindItem( pCLCList, (MLC_FIND_FUNC)s_CSM_FindSessionByCCHandle, &CCHandle, ltLockType, ppLockRef, (void**)&pSession ); if ( rv == CSSM_OK ) { ASSERT_VALID_CSM_SESSION( pSession ); *ppFoundSession = pSession; } else { if ( rv == MLC_ERR_NOT_FOUND ) { /* Don't wrap this case in the ERR() macro because this * error should only happen if the CSSM or the CSP has a * context state problem, or if the CSP is making sure * that an operation has NOT been started using the context * handle. */ rv = CSSMERR_CSP_STAGED_OPERATION_NOT_STARTED; } else { ERR( rv = CSSMERR_CSP_INTERNAL_ERROR ); } } /* MLC_FindItem */ } /* Validation */ return rv; } CSSM_RETURN CSM_UnlockStagedSession( MLC_LOCK_TYPE ltLockType, MLC_LOCK_REF LockRef ) { MLC_ReleaseItem( ltLockType, LockRef ); return CSSM_OK; } CSSM_RETURN CSM_DuplicateStagedSession( CSM_SESSION_LIST *pList, CSSM_CC_HANDLE SrcCCHandle, CSSM_CC_HANDLE DestCCHandle, CSM_ALG_STATE_DUPLICATOR DupState ) { CSSM_RETURN rv; const CSM_SESSION *pSrcSession = NULL; CSM_SESSION *pDestSession = NULL; MLC_LOCK_REF SrcLockRef; MLC_LOCK_REF DestLockRef; void *pDestState = NULL; if ( pList == NULL ) { ERR( rv = CSSMERR_CSP_INTERNAL_ERROR ); } else { /* Find the source session */ if ( ( rv = CSM_FindStagedSession( pList, SrcCCHandle, MLC_READ_LOCK, (CSM_SESSION**)&pSrcSession, &SrcLockRef ) ) == CSSM_OK ) { ASSERT_VALID_CSM_SESSION( pSrcSession ); /* Check to make sure the session type is valid */ if ( pSrcSession->SessionType != CSM_ST_DIGEST ) { ERR( rv = CSSMERR_CSP_INVALID_CONTEXT ); } else { /* Create the new session */ if ( ( rv = CSM_CreateStagedSession( pList, pSrcSession->hCsp, DestCCHandle, pSrcSession->pContext, pSrcSession->SessionType, &pDestSession, &DestLockRef ) ) == CSSM_OK ) { /* Duplicate any source session state information */ if ( pSrcSession->pCryptoState != NULL ) { /* Assume flat buffer and copy it */ pDestState = Addin_malloc( pSrcSession->uCryptoStateSize, NULL ); if ( pDestState == NULL ) { ERR( rv = CSSMERR_CSP_MEMORY_ERROR ); } else { memcpy( pDestState, pSrcSession->pCryptoState, pSrcSession->uCryptoStateSize ); /* Assign the duplicated state and size */ pDestSession->uCryptoStateSize = pSrcSession->uCryptoStateSize; pDestSession->pCryptoState = pDestState; #ifdef CSM_TRUSTWAY rv = ADDIN_CSM_DigestDataClone(pSrcSession, pDestSession); #else /* Perform custom copy operations */ if ( DupState != NULL ) { /* Duplication function provided */ rv = DupState( pSrcSession->pContext, pSrcSession->pCryptoState, pSrcSession->uCryptoStateSize, pDestState ); } #endif } /* Addin_malloc */ } /* pCryptoState != NULL */ /* Unlock the new session */ CSM_UnlockStagedSession( MLC_WRITE_LOCK, DestLockRef ); /* Delete the new session is copying the state failed */ if ( rv != CSSM_OK ) { CSM_DeleteStagedSession( pList, pDestSession ); } } /* CSM_CreateStagedSession */ } /* Check context type */ /* Release the destination lock */ CSM_UnlockStagedSession( MLC_READ_LOCK, SrcLockRef ); } /* CSM_FindStagedSession */ } /* Validation */ return rv; } CSSM_RETURN CSM_GetSessionType( CSSM_CONTEXT_TYPE ContextType, CSSM_BOOL bForward, CSM_SESSION_TYPE *pSessionType ) { switch ( ContextType ) { case CSSM_ALGCLASS_NONE: { *pSessionType = CSM_ST_NONE; break; } case CSSM_ALGCLASS_CUSTOM: { *pSessionType = CSM_ST_CUSTOM; break; } case CSSM_ALGCLASS_SIGNATURE: { *pSessionType = CSM_ST_SIGN; break; } case CSSM_ALGCLASS_SYMMETRIC: case CSSM_ALGCLASS_ASYMMETRIC: { if ( bForward != CSSM_FALSE ) { *pSessionType = CSM_ST_ENCRYPT; } else { *pSessionType = CSM_ST_DECRYPT; } break; } case CSSM_ALGCLASS_DIGEST: { *pSessionType = CSM_ST_DIGEST; break; } case CSSM_ALGCLASS_RANDOMGEN: { *pSessionType = CSM_ST_RANDOMGEN; break; } case CSSM_ALGCLASS_UNIQUEGEN: { *pSessionType = CSM_ST_UNIQUEGEN; break; } case CSSM_ALGCLASS_MAC: { *pSessionType = CSM_ST_GEN_MAC; break; } case CSSM_ALGCLASS_KEYGEN: { *pSessionType = CSM_ST_KEYGEN; break; } case CSSM_ALGCLASS_DERIVEKEY: { *pSessionType = CSM_ST_DERIVE; break; } default: { return CSSMERR_CSP_INVALID_CONTEXT; } } return CSSM_OK; }