//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1995. // // File: pct1msg.c // // Contents: // // Classes: // // Functions: // // History: 09-23-97 jbanes LSA integration stuff. // //---------------------------------------------------------------------------- #include #include #include static SP_STATUS Pct1ComputeMac( PSPContext pContext, BOOL fWriteMAC, PSPBuffer pData, DWORD dwSequence, PBYTE pbMac, PDWORD pcbMac); Pct1CipherMap Pct1CipherRank[] = { {CALG_RC4, 128, PCT1_CIPHER_RC4 | PCT1_ENC_BITS_128 | PCT1_MAC_BITS_128}, {CALG_RC4, 64, PCT1_CIPHER_RC4 | PCT1_ENC_BITS_64 | PCT1_MAC_BITS_128}, {CALG_RC4, 40, PCT1_CIPHER_RC4 | PCT1_ENC_BITS_40 | PCT1_MAC_BITS_128}, }; DWORD Pct1NumCipher = sizeof(Pct1CipherRank)/sizeof(Pct1CipherMap); /* available hashes, in order of preference */ Pct1HashMap Pct1HashRank[] = { {CALG_MD5, PCT1_HASH_MD5}, {CALG_SHA, PCT1_HASH_SHA} }; DWORD Pct1NumHash = sizeof(Pct1HashRank)/sizeof(Pct1HashMap); CertTypeMap aPct1CertEncodingPref[] = { { X509_ASN_ENCODING , PCT1_CERT_X509_CHAIN }, { X509_ASN_ENCODING , PCT1_CERT_X509 } }; DWORD cPct1CertEncodingPref = sizeof(aPct1CertEncodingPref)/sizeof(CertTypeMap); KeyTypeMap aPct1LocalExchKeyPref[] = // CAPI Key type, SCHANNEL ALGID { { CALG_RSA_KEYX, SP_EXCH_RSA_PKCS1 } }; DWORD cPct1LocalExchKeyPref = sizeof(aPct1LocalExchKeyPref)/sizeof(KeyTypeMap); KeyTypeMap aPct1LocalSigKeyPref[] = // CAPI Key type, SCHANNEL ALGID { { CALG_RSA_KEYX, SP_SIG_RSA_MD5 }, { CALG_RSA_KEYX, SP_SIG_RSA_SHA } }; DWORD cPct1LocalSigKeyPref = sizeof(aPct1LocalSigKeyPref)/sizeof(KeyTypeMap); SP_STATUS WINAPI Pct1EncryptRaw( PSPContext pContext, PSPBuffer pAppInput, PSPBuffer pCommOutput, DWORD dwFlags) { SP_STATUS pctRet; DWORD cPadding; SPBuffer Encrypted; BOOL fEscape; DWORD cbHeader; DWORD cbBlockSize; BYTE rgbMac[SP_MAX_DIGEST_LEN]; DWORD cbMac; fEscape = (0 != (dwFlags & PCT1_ENCRYPT_ESCAPE)); cbBlockSize = pContext->pCipherInfo->dwBlockSize; cPadding = pAppInput->cbData & (cbBlockSize - 1); if(cPadding) { cPadding = cbBlockSize - cPadding; } if(fEscape || (cbBlockSize > 1)) { cbHeader = sizeof(PCT1_MESSAGE_HEADER_EX); } else { cbHeader = sizeof(PCT1_MESSAGE_HEADER); } if(pCommOutput->cbBuffer < (cbHeader + cPadding + pAppInput->cbData)) { return PCT_INT_BUFF_TOO_SMALL; } Encrypted.pvBuffer = (PUCHAR)pCommOutput->pvBuffer + cbHeader; Encrypted.cbBuffer = pCommOutput->cbBuffer - cbHeader; Encrypted.cbData = pAppInput->cbData; // Copy input data to output buffer (we're encrypting in place). if(pAppInput->pvBuffer != Encrypted.pvBuffer) { DebugLog((DEB_WARN, "Pct1EncryptRaw: Unnecessary Move, performance hog\n")); MoveMemory(Encrypted.pvBuffer, pAppInput->pvBuffer, pAppInput->cbData); } /* Generate Padding */ pctRet = GenerateRandomBits((PUCHAR)Encrypted.pvBuffer + Encrypted.cbData, cPadding); if(!NT_SUCCESS(pctRet)) { return SP_LOG_RESULT(pctRet); } Encrypted.cbData += cPadding; DebugLog((DEB_TRACE, "Sealing message %x\n", pContext->WriteCounter)); // Transfer the write key over from the application process. if(pContext->hWriteKey == 0) { DebugLog((DEB_TRACE, "Transfer write key from user process.\n")); pctRet = SPGetUserKeys(pContext, SCH_FLAG_WRITE_KEY); if(pctRet != PCT_ERR_OK) { return SP_LOG_RESULT(pctRet); } } // Compute the MAC. cbMac = sizeof(rgbMac); pctRet = Pct1ComputeMac(pContext, TRUE, &Encrypted, pContext->WriteCounter, rgbMac, &cbMac); if(pctRet != PCT_ERR_OK) { return SP_LOG_RESULT(pctRet); } pContext->WriteCounter ++ ; // Encrypt data. if(!CryptEncrypt(pContext->hWriteKey, 0, FALSE, 0, Encrypted.pvBuffer, &Encrypted.cbData, Encrypted.cbBuffer)) { SP_LOG_RESULT(GetLastError()); return PCT_INT_INTERNAL_ERROR; } // Add MAC to encrypted buffer. if(Encrypted.cbData + cbMac > Encrypted.cbBuffer) { return PCT_INT_BUFF_TOO_SMALL; } CopyMemory((PUCHAR)Encrypted.pvBuffer + Encrypted.cbData, rgbMac, cbMac); Encrypted.cbData += cbMac; /* set sizes */ if(fEscape || (cbBlockSize > 1)) { if(Encrypted.cbData > 0x3fff) { return PCT_INT_DATA_OVERFLOW; } ((PUCHAR)pCommOutput->pvBuffer)[0]= (UCHAR)(0x3f & (Encrypted.cbData>>8)); if(fEscape) { ((PUCHAR)pCommOutput->pvBuffer)[0] |= 0x40; } ((PUCHAR)pCommOutput->pvBuffer)[1]= (UCHAR)(0xff & Encrypted.cbData); ((PUCHAR)pCommOutput->pvBuffer)[2]= (UCHAR)cPadding; } else { if(Encrypted.cbData > 0x7fff) { return PCT_INT_DATA_OVERFLOW; } ((PUCHAR)pCommOutput->pvBuffer)[0]= (UCHAR)(0x7f & (Encrypted.cbData>>8)) | 0x80; ((PUCHAR)pCommOutput->pvBuffer)[1]= (UCHAR)(0xff & Encrypted.cbData); } pCommOutput->cbData = Encrypted.cbData + cbHeader; #if DBG { DWORD di; CHAR KeyDispBuf[SP_MAX_DIGEST_LEN*2+1]; for(di=0;dicbData < 1) { return (PCT_INT_INCOMPLETE_MSG); } if( ((PUCHAR)pCommInput->pvBuffer)[0]&0x80 ) { *pcbHeaderSize = 2; } else { *pcbHeaderSize = 3; } return PCT_ERR_OK; } SP_STATUS WINAPI Pct1DecryptMessage(PSPContext pContext, PSPBuffer pMessage, PSPBuffer pAppOutput) { SP_STATUS pctRet; DWORD cbHeader; DWORD cbPadding; DWORD cbPayload; DWORD cbActualData; SPBuffer Encrypted; PUCHAR pbMAC; BYTE rgbMac[SP_MAX_DIGEST_LEN]; DWORD cbMac; cbActualData = pMessage->cbData; // Do we have a complete header? pMessage->cbData = 2; if(cbActualData < 2) { return PCT_INT_INCOMPLETE_MSG; } if(((PUCHAR)pMessage->pvBuffer)[0] & 0x80) { cbHeader = 2; cbPadding = 0; cbPayload = MAKEWORD(((PUCHAR)pMessage->pvBuffer)[1], ((PUCHAR)pMessage->pvBuffer)[0] & 0x7f); } else { // Do we still have a complete header? cbHeader = 3; pMessage->cbData++; if(cbActualData < cbHeader) { return PCT_INT_INCOMPLETE_MSG; } cbPadding = ((PUCHAR)pMessage->pvBuffer)[2]; cbPayload = MAKEWORD(((PUCHAR)pMessage->pvBuffer)[1], ((PUCHAR)pMessage->pvBuffer)[0] & 0x3f); } // Do we have the complete message? pMessage->cbData += cbPayload; if(cbActualData < cbHeader + cbPayload) { return PCT_INT_INCOMPLETE_MSG; } /* do we have enough data for our checksum */ if(cbPayload < pContext->pHashInfo->cbCheckSum) { return SP_LOG_RESULT(PCT_INT_MSG_ALTERED); } Encrypted.pvBuffer = (PUCHAR)pMessage->pvBuffer + cbHeader; Encrypted.cbBuffer = cbPayload - pContext->pHashInfo->cbCheckSum; Encrypted.cbData = Encrypted.cbBuffer; pbMAC = (PUCHAR)Encrypted.pvBuffer + Encrypted.cbData; /* check to see if we have a block size violation */ if(Encrypted.cbData % pContext->pCipherInfo->dwBlockSize) { return SP_LOG_RESULT(PCT_INT_MSG_ALTERED); } Encrypted.cbBuffer = Encrypted.cbData; // Decrypt message. if(Encrypted.cbData > pAppOutput->cbBuffer) { return SP_LOG_RESULT(PCT_INT_BUFF_TOO_SMALL); } if(Encrypted.pvBuffer != pAppOutput->pvBuffer) { DebugLog((DEB_WARN, "Pct1DecryptMessage: Unnecessary MoveMemory, performance hog\n")); MoveMemory(pAppOutput->pvBuffer, Encrypted.pvBuffer, Encrypted.cbData); } pAppOutput->cbData = Encrypted.cbData; // Transfer the read key over from the application process. if(pContext->hReadKey == 0) { DebugLog((DEB_TRACE, "Transfer read key from user process.\n")); pctRet = SPGetUserKeys(pContext, SCH_FLAG_READ_KEY); if(pctRet != PCT_ERR_OK) { return SP_LOG_RESULT(pctRet); } } if(!CryptDecrypt(pContext->hReadKey, 0, FALSE, 0, pAppOutput->pvBuffer, &pAppOutput->cbData)) { SP_LOG_RESULT(GetLastError()); return PCT_INT_INTERNAL_ERROR; } // Compute MAC cbMac = sizeof(rgbMac); pctRet = Pct1ComputeMac(pContext, FALSE, pAppOutput, pContext->ReadCounter, rgbMac, &cbMac); if(pctRet != PCT_ERR_OK) { return SP_LOG_RESULT(pctRet); } pContext->ReadCounter++; #if DBG { DWORD di; CHAR KeyDispBuf[SP_MAX_DIGEST_LEN*2+1]; for(di=0;dipHashInfo->cbCheckSum;di++) wsprintf(KeyDispBuf+(di*2), "%2.2x", pbMAC[di]); DebugLog((DEB_TRACE, " Incoming MAC\t%s\n", KeyDispBuf)); for(di=0;di pAppOutput->cbData) { return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG); } pAppOutput->cbData -= cbPadding; return( PCT_ERR_OK ); } #if 0 SP_STATUS PctComputeKey(PSPContext pContext, PBYTE pKey, DWORD cbKey, PUCHAR pConst, DWORD dwCLen, DWORD fFlags) { DWORD pctRet; HashBuf HBHash; PCheckSumBuffer pHash; PSessCacheItem pZombie=NULL; PSPCredentialGroup pCred=NULL; BYTE i,j; DWORD iMax; BYTE Buffer[MAX_CHECKSUM]; pZombie = pContext->RipeZombie; pCred = pZombie ->pCred; SP_BEGIN("PctComputeKey"); pHash = (PCheckSumBuffer)HBHash; iMax = (cbKey + pContext->pHashInfo->cbCheckSum - 1)/pContext->pHashInfo->cbCheckSum; if(iMax > 4) { SP_RETURN(PCT_INT_INTERNAL_ERROR); } for(i=1; i <= iMax; i++) { InitHashBuf(HBHash, pContext); pContext->pHashInfo->System->Sum( pHash, 1, &i ); if (!(fFlags & PCT_MAKE_MAC)) { // constant^i pContext->pHashInfo->System->Sum( pHash, dwCLen*i, pConst); } // MASTER KEY pContext->pHashInfo->System->Sum( pHash, pContext->RipeZombie->cbMasterKey, pContext->RipeZombie->pMasterKey); // constant^i pContext->pHashInfo->System->Sum( pHash, dwCLen*i, pConst); // ConnectionID pContext->pHashInfo->System->Sum( pHash, pContext->cbConnectionID, pContext->pConnectionID); // constant^i pContext->pHashInfo->System->Sum( pHash, dwCLen*i, pConst); if (fFlags & PCT_USE_CERT) { /* add in the certificate */ pContext->pHashInfo->System->Sum( pHash, pZombie->cbServerCertificate, pZombie->pbServerCertificate ); // constant^i pContext->pHashInfo->System->Sum( pHash, dwCLen*i, pConst); } // ConnectionID pContext->pHashInfo->System->Sum( pHash, pContext->cbChallenge, pContext->pChallenge); // constant^i pContext->pHashInfo->System->Sum( pHash, dwCLen*i, pConst); if(pContext->pHashInfo->cbCheckSum*i <= cbKey) { pContext->pHashInfo->System->Finalize( pHash, pKey + pContext->pHashInfo->cbCheckSum*(i-1) ); } else { pContext->pHashInfo->System->Finalize( pHash, Buffer ); CopyMemory(pKey + pContext->pHashInfo->cbCheckSum*(i-1), Buffer, cbKey - pContext->pHashInfo->cbCheckSum*(i-1)); } } SP_RETURN(PCT_ERR_OK); } #endif #if 0 SP_STATUS PctComputeExportKey(PSPContext pContext, PBYTE pKey, DWORD cbWriteKey, DWORD cbCipherKey) { DWORD pctRet; HashBuf HBHash; PCheckSumBuffer pHash; PSessCacheItem pZombie=NULL; PSPCredentialGroup pCred=NULL; BYTE i,j; DWORD d; DWORD cbClearChunk; BYTE pWriteKey[SP_MAX_MASTER_KEY]; BYTE Buffer[MAX_CHECKSUM]; pZombie = pContext->RipeZombie; pCred = pZombie ->pCred; SP_BEGIN("PctComputeKey"); pHash = (PCheckSumBuffer)HBHash; CopyMemory(pWriteKey, pKey, cbWriteKey); d = (cbCipherKey + pContext->pHashInfo->cbCheckSum - 1)/pContext->pHashInfo->cbCheckSum; if(d > 4) { SP_RETURN(PCT_INT_INTERNAL_ERROR); } cbClearChunk = pContext->RipeZombie->cbClearKey/d; for(i=1; i <= d; i++) { InitHashBuf(HBHash, pContext); pContext->pHashInfo->System->Sum( pHash, 1, &i ); // constant^i pContext->pHashInfo->System->Sum( pHash, PCT_CONST_SLK_LEN*i, PCT_CONST_SLK); // WRITE_KEY pContext->pHashInfo->System->Sum( pHash, cbWriteKey, pWriteKey); // constant^i pContext->pHashInfo->System->Sum( pHash, PCT_CONST_SLK_LEN*i, PCT_CONST_SLK); // Clear Key pContext->pHashInfo->System->Sum( pHash, cbClearChunk, (PBYTE)pContext->RipeZombie->pClearKey + (i-1)*cbClearChunk); if(pContext->pHashInfo->cbCheckSum*i <= cbCipherKey) { pContext->pHashInfo->System->Finalize( pHash, pKey + pContext->pHashInfo->cbCheckSum*(i-1) ); } else { pContext->pHashInfo->System->Finalize( pHash, Buffer ); CopyMemory(pKey + pContext->pHashInfo->cbCheckSum*(i-1), Buffer, cbCipherKey - pContext->pHashInfo->cbCheckSum*(i-1)); } } SP_RETURN(PCT_ERR_OK); } #endif #if 0 SP_STATUS Pct1MakeSessionKeys( PSPContext pContext) { SP_STATUS pctRet; BOOL fClient; UCHAR pWriteKey[SP_MAX_MASTER_KEY], pReadKey[SP_MAX_MASTER_KEY]; #if DBG DWORD i; CHAR KeyDispBuf[SP_MAX_MASTER_KEY*2+1]; #endif PSessCacheItem pZombie=NULL; PSPCredentialGroup pCred=NULL; SP_BEGIN("PctMakeSessionKeys"); pZombie = pContext->RipeZombie; pCred = pZombie ->pCred; if (!pContext->InitMACState) { SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR)); } #if DBG DebugLog((DEB_TRACE, "Making session keys\n", KeyDispBuf)); for(i=0;ipConnectionID[i]); DebugLog((DEB_TRACE, " ConnId\t%s\n", KeyDispBuf)); for(i=0;ipChallenge[i]); DebugLog((DEB_TRACE, " Challenge \t%s\n", KeyDispBuf)); for(i=0;iRipeZombie->cbClearKey;i++) wsprintf(KeyDispBuf+(i*2), "%2.2x", (UCHAR)pContext->RipeZombie->pClearKey[i]); DebugLog((DEB_TRACE, " ClearKey \t%s\n", KeyDispBuf)); #endif fClient = ((pContext->Flags & CONTEXT_FLAG_CLIENT) != 0); pctRet = PctComputeKey( pContext, fClient?pWriteKey:pReadKey, pContext->pCipherInfo->cbSecret, PCT_CONST_CWK, PCT_CONST_CWK_LEN, PCT_USE_CERT); if(PCT_ERR_OK != pctRet) { goto quit; } pctRet = PctComputeKey( pContext, fClient?pReadKey:pWriteKey, pContext->pCipherInfo->cbSecret, PCT_CONST_SWK, PCT_CONST_SWK_LEN, 0); if(PCT_ERR_OK != pctRet) { goto quit; } /* compute the ClientMacKey */ pctRet = PctComputeKey(pContext, (fClient?pContext->WriteMACKey:pContext->ReadMACKey), pContext->pHashInfo->cbCheckSum, PCT_CONST_CMK, PCT_CONST_CMK_LEN, PCT_USE_CERT | PCT_MAKE_MAC); if(PCT_ERR_OK != pctRet) { goto quit; } /* compute the ServerMacKey */ pctRet = PctComputeKey(pContext, (fClient?pContext->ReadMACKey:pContext->WriteMACKey), pContext->pHashInfo->cbCheckSum, PCT_CONST_SMK, PCT_CONST_SMK_LEN, PCT_MAKE_MAC); if(PCT_ERR_OK != pctRet) { goto quit; } // Initialize the hash states InitHashBuf(pContext->RdMACBuf, pContext); InitHashBuf(pContext->WrMACBuf, pContext); // Note, we truncuate the MACing keys down to the negotiated key size pContext->ReadMACState = (PCheckSumBuffer)pContext->RdMACBuf; pContext->pHashInfo->System->Sum( pContext->ReadMACState, pContext->pHashInfo->cbCheckSum, pContext->ReadMACKey); pContext->WriteMACState = (PCheckSumBuffer)pContext->WrMACBuf; pContext->pHashInfo->System->Sum( pContext->WriteMACState, pContext->pHashInfo->cbCheckSum, pContext->WriteMACKey); if (pContext->pCipherInfo->cbSecret < pContext->pCipherInfo->cbKey) { pctRet = PctComputeExportKey(pContext, pWriteKey, pContext->pCipherInfo->cbSecret, pContext->pCipherInfo->cbKey); if(PCT_ERR_OK != pctRet) { goto quit; } pctRet = PctComputeExportKey(pContext, pReadKey, pContext->pCipherInfo->cbSecret, pContext->pCipherInfo->cbKey); if(PCT_ERR_OK != pctRet) { goto quit; } /* chop the encryption keys down to selected length */ } #if DBG for(i=0;iRipeZombie->cbMasterKey;i++) wsprintf(KeyDispBuf+(i*2), "%2.2x", pContext->RipeZombie->pMasterKey[i]); DebugLog((DEB_TRACE, " MasterKey \t%s\n", KeyDispBuf)); for(i=0;ipCipherInfo->cbKey;i++) wsprintf(KeyDispBuf+(i*2), "%2.2x", pReadKey[i]); DebugLog((DEB_TRACE, " ReadKey\t%s\n", KeyDispBuf)); for(i=0;ipHashInfo->cbCheckSum;i++) wsprintf(KeyDispBuf+(i*2), "%2.2x", pContext->ReadMACKey[i]); DebugLog((DEB_TRACE, " MACKey\t%s\n", KeyDispBuf)); for(i=0;ipCipherInfo->cbKey;i++) wsprintf(KeyDispBuf+(i*2), "%2.2x", pWriteKey[i]); DebugLog((DEB_TRACE, " WriteKey\t%s\n", KeyDispBuf)); for(i=0;ipHashInfo->cbCheckSum;i++) wsprintf(KeyDispBuf+(i*2), "%2.2x", pContext->WriteMACKey[i]); DebugLog((DEB_TRACE, " MACKey\t%s\n", KeyDispBuf)); #endif if (pContext->pCipherInfo->System->Initialize( pReadKey, pContext->pCipherInfo->cbKey, pZombie->pKeyArgs, // IV pZombie->cbKeyArgs, // IV length &pContext->pReadState ) ) { if (pContext->pCipherInfo->System->Initialize( pWriteKey, pContext->pCipherInfo->cbKey, pZombie->pKeyArgs, // IV pZombie->cbKeyArgs, // IV length &pContext->pWriteState) ) { pctRet = PCT_ERR_OK; goto quit; } pctRet = SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR); pContext->pCipherInfo->System->Discard( &pContext->pReadState ); } pctRet = SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR); quit: SP_RETURN(pctRet); } #endif SP_STATUS WINAPI Pct1DecryptHandler(PSPContext pContext, PSPBuffer pCommInput, PSPBuffer pAppOutput) { SP_STATUS pctRet= 0; BOOL fEscape; PPCT1_CLIENT_HELLO pHello; if(pCommInput->cbData > 0) { /* first, we'll handle incoming data packets */ if((pContext->State == SP_STATE_CONNECTED) && (pContext->Decrypt)) { fEscape = (((*(PUCHAR)pCommInput->pvBuffer) & 0xc0) == 0x40); /* BUGFIX: IE 3.0 and 3.0a incorrectly respond to a REDO request * by just sending a PCT1 client hello, instead of another REDO. * We therefore look at the incomming message and see if it * looks like a PCT1 client hello. */ pHello = (PPCT1_CLIENT_HELLO)pCommInput->pvBuffer; if((pCommInput->cbData >= 5) && (pHello->MessageId == PCT1_MSG_CLIENT_HELLO) && (pHello->VersionMsb == MSBOF(PCT_VERSION_1)) && (pHello->VersionLsb == LSBOF(PCT_VERSION_1)) && (pHello->OffsetMsb == MSBOF(PCT_CH_OFFSET_V1)) && (pHello->OffsetLsb == LSBOF(PCT_CH_OFFSET_V1))) { // This looks a lot like a client hello /* InitiateRedo */ pAppOutput->cbData = 0; pCommInput->cbData = 0; pContext->State = PCT1_STATE_RENEGOTIATE; ; return SP_LOG_RESULT(PCT_INT_RENEGOTIATE); } if(PCT_ERR_OK == (pctRet = pContext->Decrypt(pContext, pCommInput, /* message */ pAppOutput /* Unpacked Message */ ))) { /* look for escapes */ if(fEscape) { if(pAppOutput->cbData < 1) { return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG); } /* The first byte of the decrypt buffer is the escape code */ switch(*(PUCHAR)pAppOutput->pvBuffer) { case PCT1_ET_REDO_CONN: { /* InitiateRedo */ if(pAppOutput->cbData != 1) { return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG); } pContext->State = PCT1_STATE_RENEGOTIATE; pAppOutput->cbData = 0; return SP_LOG_RESULT(PCT_INT_RENEGOTIATE); } case PCT1_ET_OOB_DATA: /* HandleOOB */ default: /* Unknown escape, generate error */ pctRet = SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG); /* Disconnect */ break; } } } return (pctRet); } else { return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG); } } return PCT_INT_INCOMPLETE_MSG; } SP_STATUS Pct1GenerateError(PSPContext pContext, PSPBuffer pCommOutput, SP_STATUS pError, PSPBuffer pErrData) { Pct1Error XmitError; /* Only pack up an error if we are allowed to return errors */ if(!(pContext->Flags & CONTEXT_FLAG_EXT_ERR)) return pError; XmitError.Error = pError; XmitError.ErrInfoLen = 0; XmitError.ErrInfo = NULL; if(pErrData) { XmitError.ErrInfoLen = pErrData->cbData; XmitError.ErrInfo = pErrData->pvBuffer; } Pct1PackError(&XmitError, pCommOutput); return pError; } /* session key computation */ SP_STATUS Pct1HandleError(PSPContext pContext, PSPBuffer pCommInput, PSPBuffer pCommOutput) { UNREFERENCED_PARAMETER(pContext); pCommOutput->cbData = 0; return(((PPCT1_ERROR)pCommInput->pvBuffer)->ErrorMsb << 8 )| ((PPCT1_ERROR)pCommInput->pvBuffer)->ErrorLsb; } //+--------------------------------------------------------------------------- // // Function: Pct1BeginVerifyPrelude // // Synopsis: Initiate the "verify prelude" computation. // // Arguments: [pContext] -- Schannel context. // [pClientHello] -- // [cbClientHello] -- // [pServerHello] -- // [cServerHello] -- // // History: 10-10-97 jbanes Added CAPI integration. // // Notes: Hash(CLIENT_MAC_KEY, Hash("cvp", CLIENT_HELLO, SERVER_HELLO)); // //---------------------------------------------------------------------------- SP_STATUS Pct1BeginVerifyPrelude(PSPContext pContext, PUCHAR pClientHello, DWORD cbClientHello, PUCHAR pServerHello, DWORD cbServerHello) { HCRYPTHASH hHash; if(!CryptCreateHash(pContext->RipeZombie->hMasterProv, pContext->pHashInfo->aiHash, 0, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); return PCT_INT_INTERNAL_ERROR; } if(!CryptHashData(hHash, (PBYTE)PCT_CONST_VP, PCT_CONST_VP_LEN, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return PCT_INT_INTERNAL_ERROR; } if(!CryptHashData(hHash, pClientHello, cbClientHello, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return PCT_INT_INTERNAL_ERROR; } if(!CryptHashData(hHash, pServerHello, cbServerHello, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return PCT_INT_INTERNAL_ERROR; } pContext->hMd5Handshake = hHash; return PCT_ERR_OK; } //+--------------------------------------------------------------------------- // // Function: Pct1EndVerifyPrelude // // Synopsis: Finish the "verify prelude" computation. // // Arguments: [pContext] -- Schannel context. // [VerifyPrelude] -- // [pcbVerifyPrelude] -- // // History: 10-10-97 jbanes Added CAPI integration. // // Notes: // //---------------------------------------------------------------------------- SP_STATUS Pct1EndVerifyPrelude(PSPContext pContext, PUCHAR VerifyPrelude, DWORD * pcbVerifyPrelude) { BOOL fClient; HCRYPTHASH hHash; fClient = !(pContext->RipeZombie->fProtocol & SP_PROT_SERVERS); if(!CryptGetHashParam(pContext->hMd5Handshake, HP_HASHVAL, VerifyPrelude, pcbVerifyPrelude, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(pContext->hMd5Handshake); pContext->hMd5Handshake = 0; return PCT_INT_INTERNAL_ERROR; } CryptDestroyHash(pContext->hMd5Handshake); pContext->hMd5Handshake = 0; if(!CryptCreateHash(pContext->RipeZombie->hMasterProv, pContext->pHashInfo->aiHash, 0, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); return PCT_INT_INTERNAL_ERROR; } if(!CryptHashSessionKey(hHash, fClient ? pContext->hWriteMAC : pContext->hReadMAC, CRYPT_LITTLE_ENDIAN)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return PCT_INT_INTERNAL_ERROR; } if(!CryptHashData(hHash, VerifyPrelude, *pcbVerifyPrelude, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return PCT_INT_INTERNAL_ERROR; } if(!CryptGetHashParam(hHash, HP_HASHVAL, VerifyPrelude, pcbVerifyPrelude, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return PCT_INT_INTERNAL_ERROR; } CryptDestroyHash(hHash); return PCT_ERR_OK; } //+--------------------------------------------------------------------------- // // Function: Pct1ComputeMac // // Synopsis: Compute the // // Arguments: [pContext] -- Schannel context. // // History: 10-10-97 jbanes Created. // // Notes: MAC_DATA := Hash(MAC_KEY, Hash(RECORD_HEADER_DATA, // ACTUAL_DATA, PADDING_DATA, SEQUENCE_NUMBER)) // //---------------------------------------------------------------------------- static SP_STATUS Pct1ComputeMac( PSPContext pContext, // in BOOL fWriteMAC, // in PSPBuffer pData, // in DWORD dwSequence, // in PBYTE pbMac, // out PDWORD pcbMac) // in, out { HCRYPTHASH hHash; DWORD dwReverseSequence; dwReverseSequence = htonl(dwSequence); // Compute inner hash if(!CryptCreateHash(pContext->RipeZombie->hMasterProv, pContext->pHashInfo->aiHash, 0, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); return PCT_INT_INTERNAL_ERROR; } if(!CryptHashData(hHash, pData->pvBuffer, pData->cbData, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return PCT_INT_INTERNAL_ERROR; } if(!CryptHashData(hHash, (PUCHAR)&dwReverseSequence, sizeof(DWORD), 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return PCT_INT_INTERNAL_ERROR; } if(!CryptGetHashParam(hHash, HP_HASHVAL, pbMac, pcbMac, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return PCT_INT_INTERNAL_ERROR; } SP_ASSERT(*pcbMac == pContext->pHashInfo->cbCheckSum); CryptDestroyHash(hHash); // Compute outer hash. if(!CryptCreateHash(pContext->RipeZombie->hMasterProv, pContext->pHashInfo->aiHash, 0, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); return PCT_INT_INTERNAL_ERROR; } if(!CryptHashSessionKey(hHash, fWriteMAC ? pContext->hWriteMAC : pContext->hReadMAC, CRYPT_LITTLE_ENDIAN)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return PCT_INT_INTERNAL_ERROR; } if(!CryptHashData(hHash, pbMac, *pcbMac, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return PCT_INT_INTERNAL_ERROR; } if(!CryptGetHashParam(hHash, HP_HASHVAL, pbMac, pcbMac, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return PCT_INT_INTERNAL_ERROR; } SP_ASSERT(*pcbMac == pContext->pHashInfo->cbCheckSum); CryptDestroyHash(hHash); return PCT_ERR_OK; } //+--------------------------------------------------------------------------- // // Function: Pct1ComputeResponse // // Synopsis: Compute the "response" field of the ServerVerify message. // // Arguments: [pContext] -- Schannel context. // [pbChallenge] -- // [cbChallenge] -- // [pbConnectionID] -- // [cbConnectionID] -- // [pbSessionID] -- // [cbSessionID] -- // [pbResponse] -- // [pcbResponse] -- // // History: 10-10-97 jbanes Created. // // Notes: Hash(SERVER_MAC_KEY, Hash ("sr", CH_CHALLENGE_DATA, // SH_CONNECTION_ID_DATA, SV_SESSION_ID_DATA)) // //---------------------------------------------------------------------------- SP_STATUS Pct1ComputeResponse( PSPContext pContext, // in PBYTE pbChallenge, // in DWORD cbChallenge, // in PBYTE pbConnectionID, // in DWORD cbConnectionID, // in PBYTE pbSessionID, // in DWORD cbSessionID, // in PBYTE pbResponse, // out PDWORD pcbResponse) // in, out { BOOL fClient; HCRYPTHASH hHash = 0; SP_STATUS pctRet; fClient = !(pContext->RipeZombie->fProtocol & SP_PROT_SERVERS); // // Hash ("sr", CH_CHALLENGE_DATA, SH_CONNECTION_ID_DATA, // SV_SESSION_ID_DATA). Place the result in pbResponse. // if(!CryptCreateHash(pContext->RipeZombie->hMasterProv, pContext->pHashInfo->aiHash, 0, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashData(hHash, (PBYTE)PCT_CONST_RESP, PCT_CONST_RESP_LEN, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashData(hHash, pbChallenge, cbChallenge, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashData(hHash, pbConnectionID, cbConnectionID, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashData(hHash, pbSessionID, cbSessionID, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptGetHashParam(hHash, HP_HASHVAL, pbResponse, pcbResponse, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } CryptDestroyHash(hHash); hHash = 0; // // Hash (SERVER_MAC_KEY, pbResponse). Place the result back in pbResponse. // if(!CryptCreateHash(pContext->RipeZombie->hMasterProv, pContext->pHashInfo->aiHash, 0, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashSessionKey(hHash, fClient ? pContext->hReadMAC : pContext->hWriteMAC, CRYPT_LITTLE_ENDIAN)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashData(hHash, pbResponse, *pcbResponse, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptGetHashParam(hHash, HP_HASHVAL, pbResponse, pcbResponse, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } CryptDestroyHash(hHash); hHash = 0; pctRet = PCT_ERR_OK; cleanup: if(hHash) { CryptDestroyHash(hHash); } return pctRet; }