/*++ Copyright (c) 1994 Microsoft Corporation Module Name: ccp.c Abstract: Author: Thomas J. Dimitri (TommyD) 29-March-1994 Environment: Revision History: --*/ #include "wan.h" #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT, WanInitECP) #pragma alloc_text(INIT, WanInitVJ) #endif #define __FILE_SIG__ CCP_FILESIG NDIS_STATUS AllocateEncryptMemory( PCRYPTO_INFO CryptoInfo ); NDIS_STATUS AllocateCompressMemory( PBUNDLECB BundleCB ); NTSTATUS AllocateCryptoMSChapV1( PBUNDLECB BundleCB, PCOMPRESS_INFO CompInfo, PCRYPTO_INFO CryptoInfo, BOOLEAN IsSend ); NTSTATUS AllocateCryptoMSChapV2( PBUNDLECB BundleCB, PCOMPRESS_INFO CompInfo, PCRYPTO_INFO CryptoInfo, BOOLEAN IsSend ); #ifdef EAP_ON NTSTATUS AllocateCryptoEap( PBUNDLECB BundleCB, PCOMPRESS_INFO CompInfo, PCRYPTO_INFO CryptoInfo, BOOLEAN IsSend ); #endif NPAGED_LOOKASIDE_LIST EncryptCtxList; // List of free encryption contexts NPAGED_LOOKASIDE_LIST CachedKeyList; // List of free encryption contexts #ifdef ENCRYPT_128BIT NPAGED_LOOKASIDE_LIST CachedKeyListLong; // List of free encryption contexts #endif VOID WanInitECP( VOID ) { NdisInitializeNPagedLookasideList(&EncryptCtxList, NULL, NULL, 0, ENCRYPTCTX_SIZE, ENCRYPTCTX_TAG, 0); NdisInitializeNPagedLookasideList(&CachedKeyList, NULL, NULL, 0, glCachedKeyCount * (sizeof(USHORT) + MAX_SESSIONKEY_SIZE), CACHEDKEY_TAG, 0); #ifdef ENCRYPT_128BIT NdisInitializeNPagedLookasideList(&CachedKeyListLong, NULL, NULL, 0, glCachedKeyCount * (sizeof(USHORT) + MAX_USERSESSIONKEY_SIZE), CACHEDKEY_TAG, 0); #endif } VOID WanDeleteECP( VOID ) { NdisDeleteNPagedLookasideList(&EncryptCtxList); NdisDeleteNPagedLookasideList(&CachedKeyList); #ifdef ENCRYPT_128BIT NdisDeleteNPagedLookasideList(&CachedKeyListLong); #endif } // // Assumes the endpoint lock is held // NTSTATUS WanAllocateECP( PBUNDLECB BundleCB, PCOMPRESS_INFO CompInfo, PCRYPTO_INFO CryptoInfo, BOOLEAN IsSend ) { NTSTATUS Status = STATUS_SUCCESS; NdisWanDbgOut(DBG_TRACE, DBG_CCP, ("WanAllocateECP: Enter")); // // Is encryption enabled? // #ifdef ENCRYPT_128BIT if ((CompInfo->MSCompType & (NDISWAN_ENCRYPTION | NDISWAN_40_ENCRYPTION | NDISWAN_56_ENCRYPTION | NDISWAN_128_ENCRYPTION))) { #else if ((CompInfo->MSCompType & (NDISWAN_ENCRYPTION | NDISWAN_40_ENCRYPTION | NDISWAN_56_ENCRYPTION))) { #endif if (CryptoInfo->Context == NULL) { Status = AllocateEncryptMemory(CryptoInfo); if (Status != NDIS_STATUS_SUCCESS) { NdisWanDbgOut(DBG_FAILURE, DBG_CCP, ("Can't allocate encryption key!")); return(STATUS_INSUFFICIENT_RESOURCES); } } do { CryptoInfo->Flags |= (CompInfo->Flags & CCP_IS_SERVER) ? CRYPTO_IS_SERVER : 0; if (CompInfo->AuthType == AUTH_USE_MSCHAPV1) { Status = AllocateCryptoMSChapV1(BundleCB, CompInfo, CryptoInfo, IsSend); } else if (CompInfo->AuthType == AUTH_USE_MSCHAPV2) { Status = AllocateCryptoMSChapV2(BundleCB, CompInfo, CryptoInfo, IsSend); #ifdef EAP_ON } else if (CompInfo->AuthType == AUTH_USE_EAP) { Status = AllocateCryptoEap(BundleCB, CompInfo, CryptoInfo, IsSend); #endif } else { Status = STATUS_UNSUCCESSFUL; break; } if (!IsSend && CryptoInfo->CachedKeyBuffer == NULL) { #ifdef DBG_ECP DbgPrint("NDISWAN: CompInfo = %p\n", CompInfo); DbgPrint("NDISWAN: CryptoInfo = %p\n", CryptoInfo); DbgPrint("NDISWAN: MSCompType = %0x\n", CompInfo->MSCompType); DbgPrint("NDISWAN: Flags = %0x\n", CryptoInfo->Flags); DbgPrint("NDISWAN: SessionKeyLength = %d\n", CryptoInfo->SessionKeyLength); #endif #ifdef ENCRYPT_128BIT if ((CompInfo->MSCompType & NDISWAN_128_ENCRYPTION)) { CryptoInfo->CachedKeyBuffer = NdisAllocateFromNPagedLookasideList(&CachedKeyListLong); } else #endif { CryptoInfo->CachedKeyBuffer = NdisAllocateFromNPagedLookasideList(&CachedKeyList); } if (CryptoInfo->CachedKeyBuffer == NULL) { NdisWanDbgOut(DBG_FAILURE, DBG_CCP, ("Can't allocate cached key array!")); Status = STATUS_INSUFFICIENT_RESOURCES; break; } else { CryptoInfo->pCurrKey = (PCACHED_KEY)CryptoInfo->CachedKeyBuffer; CryptoInfo->pLastKey = (PCACHED_KEY)((PUCHAR) CryptoInfo->CachedKeyBuffer + (glCachedKeyCount - 1) * (sizeof(USHORT)+ CryptoInfo->SessionKeyLength)); NdisFillMemory(CryptoInfo->CachedKeyBuffer, glCachedKeyCount * (sizeof(USHORT)+ CryptoInfo->SessionKeyLength), 0xff); } } } while(FALSE); if (Status != STATUS_SUCCESS) { if (CryptoInfo->Context != NULL) { NdisFreeToNPagedLookasideList(&EncryptCtxList, CryptoInfo->Context); // // Clear so we know it is deallocated // CryptoInfo->Context = CryptoInfo->RC4Key= NULL; } if (CryptoInfo->CachedKeyBuffer != NULL) { #ifdef ENCRYPT_128BIT if ((CompInfo->MSCompType & NDISWAN_128_ENCRYPTION)) { NdisFreeToNPagedLookasideList(&CachedKeyListLong, CryptoInfo->CachedKeyBuffer); } else #endif { NdisFreeToNPagedLookasideList(&CachedKeyList, CryptoInfo->CachedKeyBuffer); } CryptoInfo->CachedKeyBuffer = NULL; CryptoInfo->pCurrKey = CryptoInfo->pLastKey = NULL; } NdisWanDbgOut(DBG_FAILURE, DBG_CCP, ("Failed allocating Crypto Status %x!", Status)); return (Status); } // // Next packet out is flushed // BundleCB->Flags |= RECV_PACKET_FLUSH; } NdisWanDbgOut(DBG_TRACE, DBG_CCP, ("WanAllocateECP: Exit")); return(Status); } // // Assumes the endpoint lock is held // VOID WanDeallocateECP( PBUNDLECB BundleCB, PCOMPRESS_INFO CompInfo, PCRYPTO_INFO CryptoInfo ) { NdisWanDbgOut(DBG_TRACE, DBG_CCP, ("WanDeallocateECP: Enter")); // // Deallocate encryption keys. // if (CryptoInfo->Context != NULL) { NdisFreeToNPagedLookasideList(&EncryptCtxList, CryptoInfo->Context); // // Clear so we know it is deallocated // CryptoInfo->Context = CryptoInfo->RC4Key= NULL; } if (CryptoInfo->CachedKeyBuffer != NULL) { #ifdef ENCRYPT_128BIT if ((CompInfo->MSCompType & NDISWAN_128_ENCRYPTION)) { NdisFreeToNPagedLookasideList(&CachedKeyListLong, CryptoInfo->CachedKeyBuffer); } else #endif { NdisFreeToNPagedLookasideList(&CachedKeyList, CryptoInfo->CachedKeyBuffer); } CryptoInfo->CachedKeyBuffer = NULL; CryptoInfo->pCurrKey = CryptoInfo->pLastKey = NULL; } // // Clear the encrption bits // #ifdef ENCRYPT_128BIT CompInfo->MSCompType &= ~(NDISWAN_ENCRYPTION | NDISWAN_40_ENCRYPTION | NDISWAN_56_ENCRYPTION | NDISWAN_128_ENCRYPTION); #else CompInfo->MSCompType &= ~(NDISWAN_ENCRYPTION | NDISWAN_40_ENCRYPTION | NDISWAN_56_ENCRYPTION); #endif NdisWanDbgOut(DBG_TRACE, DBG_CCP, ("WanDeallocateCCP: Exit")); } NTSTATUS AllocateCryptoMSChapV1( PBUNDLECB BundleCB, PCOMPRESS_INFO CompInfo, PCRYPTO_INFO CryptoInfo, BOOLEAN IsSend ) { if (CompInfo->MSCompType & NDISWAN_ENCRYPTION) { // // For legacy encryption we use the 8 byte LMSessionKey // for initiali encryption session key. The first 256 // packets will be sent using this without any salt // (the first 256 packets are using 64 bit encryption). // After the first 256 we will always salt the first 3 // bytes of the encryption key so that we are doing 40 // bit encryption. // CryptoInfo->SessionKeyLength = MAX_SESSIONKEY_SIZE; NdisMoveMemory(CryptoInfo->StartKey, CompInfo->LMSessionKey, CryptoInfo->SessionKeyLength); NdisMoveMemory(CryptoInfo->SessionKey, CryptoInfo->StartKey, CryptoInfo->SessionKeyLength); } else if (CompInfo->MSCompType & (NDISWAN_40_ENCRYPTION | NDISWAN_56_ENCRYPTION)) { CryptoInfo->SessionKeyLength = MAX_SESSIONKEY_SIZE; // // For our new 40/56 bit encryption we will use SHA on the // 8 byte LMSessionKey to derive our intial 8 byte // encryption session key. // NdisMoveMemory(CryptoInfo->StartKey, CompInfo->LMSessionKey, CryptoInfo->SessionKeyLength); NdisMoveMemory(CryptoInfo->SessionKey, CompInfo->LMSessionKey, CryptoInfo->SessionKeyLength); GetNewKeyFromSHA(CryptoInfo); if (CompInfo->MSCompType & NDISWAN_40_ENCRYPTION) { // // Set the first 3 bytes to reduce to // 40 bits of random key // CryptoInfo->SessionKey[0] = 0xD1; CryptoInfo->SessionKey[1] = 0x26; CryptoInfo->SessionKey[2] = 0x9E; } else { // // Set the first byte to reduce to // 56 bits of random key // CryptoInfo->SessionKey[0] = 0xD1; } #ifdef ENCRYPT_128BIT } else if (CompInfo->MSCompType & NDISWAN_128_ENCRYPTION) { CryptoInfo->SessionKeyLength = MAX_USERSESSIONKEY_SIZE; // // For our new 128 bit encryption we will use SHA on the // 16 byte NTUserSessionKey and the 8 byte Challenge to // derive our the intial 128 bit encryption session key. // NdisMoveMemory(CryptoInfo->StartKey, CompInfo->UserSessionKey, MAX_USERSESSIONKEY_SIZE); GetStartKeyFromSHA(CryptoInfo, CompInfo->Challenge); GetNewKeyFromSHA(CryptoInfo); #endif } // // Initialize the rc4 send table // NdisWanDbgOut(DBG_TRACE, DBG_CCP, ("RC4 encryption KeyLength %d", CryptoInfo->SessionKeyLength)); NdisWanDbgOut(DBG_TRACE, DBG_CCP, ("RC4 encryption Key %.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", CryptoInfo->SessionKey[0], CryptoInfo->SessionKey[1], CryptoInfo->SessionKey[2], CryptoInfo->SessionKey[3], CryptoInfo->SessionKey[4], CryptoInfo->SessionKey[5], CryptoInfo->SessionKey[6], CryptoInfo->SessionKey[7], CryptoInfo->SessionKey[8], CryptoInfo->SessionKey[9], CryptoInfo->SessionKey[10], CryptoInfo->SessionKey[11], CryptoInfo->SessionKey[12], CryptoInfo->SessionKey[13], CryptoInfo->SessionKey[14], CryptoInfo->SessionKey[15])); rc4_key(CryptoInfo->RC4Key, CryptoInfo->SessionKeyLength, CryptoInfo->SessionKey); return (STATUS_SUCCESS); } NTSTATUS AllocateCryptoMSChapV2( PBUNDLECB BundleCB, PCOMPRESS_INFO CompInfo, PCRYPTO_INFO CryptoInfo, BOOLEAN IsSend ) { NdisMoveMemory(CryptoInfo->StartKey, CompInfo->UserSessionKey, sizeof(CryptoInfo->StartKey)); if (CompInfo->MSCompType & NDISWAN_ENCRYPTION) { return(STATUS_UNSUCCESSFUL); } else if (CompInfo->MSCompType & (NDISWAN_40_ENCRYPTION | NDISWAN_56_ENCRYPTION)) { CryptoInfo->SessionKeyLength = MAX_SESSIONKEY_SIZE; #ifdef ENCRYPT_128BIT } else if (CompInfo->MSCompType & NDISWAN_128_ENCRYPTION) { CryptoInfo->SessionKeyLength = MAX_USERSESSIONKEY_SIZE; #endif } GetMasterKey(CryptoInfo, CompInfo->NTResponse); // // Setup the first key // GetAsymetricStartKey(CryptoInfo, IsSend); GetNewKeyFromSHA(CryptoInfo); if (CompInfo->MSCompType & NDISWAN_40_ENCRYPTION) { // // Set the first 3 bytes to reduce to // 40 bits of random key // CryptoInfo->SessionKey[0] = 0xD1; CryptoInfo->SessionKey[1] = 0x26; CryptoInfo->SessionKey[2] = 0x9E; } else if (CompInfo->MSCompType & NDISWAN_56_ENCRYPTION) { // // Set the first byte to reduce to // 56 bits of random key // CryptoInfo->SessionKey[0] = 0xD1; } // // Initialize the rc4 send table // NdisWanDbgOut(DBG_TRACE, DBG_CCP, ("RC4 encryption KeyLength %d", CryptoInfo->SessionKeyLength)); NdisWanDbgOut(DBG_TRACE, DBG_CCP, ("RC4 encryption Key %.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", CryptoInfo->SessionKey[0],CryptoInfo->SessionKey[1], CryptoInfo->SessionKey[2],CryptoInfo->SessionKey[3], CryptoInfo->SessionKey[4],CryptoInfo->SessionKey[5], CryptoInfo->SessionKey[6],CryptoInfo->SessionKey[7], CryptoInfo->SessionKey[8],CryptoInfo->SessionKey[9], CryptoInfo->SessionKey[10],CryptoInfo->SessionKey[11], CryptoInfo->SessionKey[12],CryptoInfo->SessionKey[13], CryptoInfo->SessionKey[14],CryptoInfo->SessionKey[15])); rc4_key(CryptoInfo->RC4Key, CryptoInfo->SessionKeyLength, CryptoInfo->SessionKey); return (STATUS_SUCCESS); } #ifdef EAP_ON NTSTATUS AllocateCryptoEap( PBUNDLECB BundleCB, PCOMPRESS_INFO CompInfo, PCRYPTO_INFO CryptoInfo, BOOLEAN IsSend ) { ULONG KeySize; KeySize = CompInfo->EapKeyLength; if (CompInfo->MSCompType & NDISWAN_ENCRYPTION) { return(STATUS_UNSUCCESSFUL); } else if (CompInfo->MSCompType & (NDISWAN_40_ENCRYPTION | NDISWAN_56_ENCRYPTION)) { // // Might need to pad this out. Spec calls for padding // at the left (front) of the value // CryptoInfo->SessionKeyLength = MAX_SESSIONKEY_SIZE; #ifdef ENCRYPT_128BIT } else if (CompInfo->MSCompType & NDISWAN_128_ENCRYPTION) { // // Might need to pad this out. Spec calls for padding // at the left (front) of the value // CryptoInfo->SessionKeyLength = MAX_USERSESSIONKEY_SIZE; #endif } NdisMoveMemory(CryptoInfo->StartKey, CompInfo->EapKey, CryptoInfo->SessionKeyLength); NdisMoveMemory(CryptoInfo->SessionKey, CryptoInfo->StartKey, CryptoInfo->SessionKeyLength); GetNewKeyFromSHA(CryptoInfo); if (CompInfo->MSCompType & NDISWAN_40_ENCRYPTION) { // // Set the first 3 bytes to reduce to // 40 bits of random key // CryptoInfo->SessionKey[0] = 0xD1; CryptoInfo->SessionKey[1] = 0x26; CryptoInfo->SessionKey[2] = 0x9E; } else if (CompInfo->MSCompType & NDISWAN_56_ENCRYPTION) { // // Set the first byte to reduce to // 56 bits of random key // CryptoInfo->SessionKey[0] = 0xD1; } // // Initialize the rc4 send table // NdisWanDbgOut(DBG_TRACE, DBG_CCP, ("RC4 encryption KeyLength %d", CryptoInfo->SessionKeyLength)); NdisWanDbgOut(DBG_TRACE, DBG_CCP, ("RC4 encryption Key %.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", CryptoInfo->SessionKey[0],CryptoInfo->SessionKey[1], CryptoInfo->SessionKey[2],CryptoInfo->SessionKey[3], CryptoInfo->SessionKey[4],CryptoInfo->SessionKey[5], CryptoInfo->SessionKey[6],CryptoInfo->SessionKey[7], CryptoInfo->SessionKey[8],CryptoInfo->SessionKey[9], CryptoInfo->SessionKey[10],CryptoInfo->SessionKey[11], CryptoInfo->SessionKey[12],CryptoInfo->SessionKey[13], CryptoInfo->SessionKey[14],CryptoInfo->SessionKey[15])); rc4_key(CryptoInfo->RC4Key, CryptoInfo->SessionKeyLength, CryptoInfo->SessionKey); return (STATUS_SUCCESS); } #endif NTSTATUS WanAllocateCCP( PBUNDLECB BundleCB, PCOMPRESS_INFO CompInfo, BOOLEAN IsSend ) { NTSTATUS Status = STATUS_SUCCESS; NdisWanDbgOut(DBG_TRACE, DBG_CCP, ("WanAllocateCCP: Enter")); if (CompInfo->MSCompType & NDISWAN_COMPRESSION) { ULONG CompressSend; ULONG CompressRecv; // // Get compression context sizes // if(BundleCB->SendCompInfo.MSCompType & NDISWAN_HISTORY_LESS) { CompressSend = sizeof(SendContext); } else { CompressSend = sizeof(SendContext) + HISTORY_SIZE; } if(BundleCB->RecvCompInfo.MSCompType & NDISWAN_HISTORY_LESS) { CompressRecv = sizeof(RecvContext) + glMRRU; } else { CompressRecv = sizeof(RecvContext) + HISTORY_SIZE; } if (IsSend) { if (BundleCB->SendCompressContext == NULL) { NdisWanAllocateMemory(&BundleCB->SendCompressContext, CompressSend, COMPCTX_TAG); // // If we can't allocate memory the machine is toast. // Forget about freeing anything up. // if (BundleCB->SendCompressContext == NULL) { NdisWanDbgOut(DBG_FAILURE, DBG_CCP, ("Can't allocate compression!")); return(STATUS_INSUFFICIENT_RESOURCES); } } ((SendContext*)BundleCB->SendCompressContext)->BundleFlags = (BundleCB->SendCompInfo.MSCompType & NDISWAN_HISTORY_LESS) ? DO_HISTORY_LESS : 0; initsendcontext (BundleCB->SendCompressContext); } else { if (BundleCB->RecvCompressContext == NULL) { NdisWanAllocateMemory(&BundleCB->RecvCompressContext, CompressRecv, COMPCTX_TAG); // // If we can't allocate memory the machine is toast. // Forget about freeing anything up. // if (BundleCB->RecvCompressContext == NULL) { NdisWanDbgOut(DBG_FAILURE, DBG_CCP, ("Can't allocate decompression")); return(STATUS_INSUFFICIENT_RESOURCES); } } if(BundleCB->RecvCompInfo.MSCompType & NDISWAN_HISTORY_LESS) { ((RecvContext*)BundleCB->RecvCompressContext)->BundleFlags = DO_HISTORY_LESS; ((RecvContext*)BundleCB->RecvCompressContext)->HistorySize = glMRRU; } else { ((RecvContext*)BundleCB->RecvCompressContext)->BundleFlags = 0; ((RecvContext*)BundleCB->RecvCompressContext)->HistorySize = HISTORY_SIZE; } // // Initialize the decompression history table // initrecvcontext (BundleCB->RecvCompressContext); } Status = STATUS_SUCCESS; // // Next packet out is flushed // BundleCB->Flags |= RECV_PACKET_FLUSH; } NdisWanDbgOut(DBG_TRACE, DBG_CCP, ("WanAllocateCCP: Exit")); return (Status); } VOID WanDeallocateCCP( PBUNDLECB BundleCB, PCOMPRESS_INFO CompInfo, BOOLEAN IsSend ) { NdisWanDbgOut(DBG_TRACE, DBG_CCP, ("WanDeallocateCCP: Enter")); if (IsSend) { if (BundleCB->SendCompressContext != NULL) { NdisWanFreeMemory(BundleCB->SendCompressContext); BundleCB->SendCompressContext= NULL; } } else { if (BundleCB->RecvCompressContext != NULL) { NdisWanFreeMemory(BundleCB->RecvCompressContext); BundleCB->RecvCompressContext= NULL; } } // // Clear the compression bits // CompInfo->MSCompType &= ~NDISWAN_COMPRESSION; NdisWanDbgOut(DBG_TRACE, DBG_CCP, ("WanDeallocateCCP: Exit")); } NDIS_STATUS AllocateEncryptMemory( PCRYPTO_INFO CryptoInfo ) { PUCHAR Mem; Mem = NdisAllocateFromNPagedLookasideList(&EncryptCtxList); if (Mem == NULL) { return (NDIS_STATUS_FAILURE); } NdisZeroMemory(Mem, ENCRYPTCTX_SIZE); CryptoInfo->Context = Mem; Mem += (sizeof(A_SHA_CTX) + sizeof(PVOID)); CryptoInfo->RC4Key = Mem; (ULONG_PTR)CryptoInfo->RC4Key &= ~((ULONG_PTR)sizeof(PVOID)-1); return(NDIS_STATUS_SUCCESS); }