Beispiel #1
0
void ZStreamR_Boundary::Imp_Read(void* oDest, size_t iCount, size_t* oCountRead)
	{
	if (not fBuffer)
		{
		fStreamSource.Read(oDest, iCount, oCountRead);
		}
	else
		{
		const size_t boundarySize = fBoundary.size();
		uint8* localDest = reinterpret_cast<uint8*>(oDest);
		while (iCount)
			{
			if (fDataEnd > fDataStart)
				{
				size_t countToMove = min(fDataEnd - fDataStart, iCount);
				sMemCopy(localDest, fBuffer + fDataStart, countToMove);
				fDataStart += countToMove;
				localDest += countToMove;
				iCount -= countToMove;
				}
			else
				{
				if (fHitBoundary)
					break;

				// Shuffle existing stuff to beginning of buffer.
				sMemMove(fBuffer, fBuffer + fDataEnd, boundarySize - fDataEnd);

				// Top up the tail.
				size_t countRead;
				fStreamSource.Read(fBuffer + boundarySize - fDataEnd, fDataEnd, &countRead);

				if (countRead < fDataEnd)
					{
					// The source stream has gone empty without our having already seen the
					// boundary. Shuffle the data we do have so the last byte aligns with
					// the end of the buffer.
					sMemMove(fBuffer + fDataEnd - countRead, fBuffer,
						boundarySize - (fDataEnd - countRead));

					// The first returnable byte is at fDataStart, and the last is at
					// the end of the buffer.
					fDataStart = fDataEnd - countRead;
					fDataEnd = boundarySize;
					if (countRead == 0)
						{
						// We read nothing at all, so fDataStart will equal fDataEnd,
						// which will be the end of the buffer. And we should bail.
						break;
						}
					}
				else
					{
					// Do Boyer-Moore search on the full buffer.
					int xx;
					for (xx = boundarySize - 1; xx >= 0 && fBuffer[xx] == fBoundary[xx]; --xx)
						{}

					if (xx < 0)
						{
						// We found the boundary.
						fHitBoundary = true;
						fDataStart = boundarySize;
						fDataEnd = boundarySize;
						}
					else
						{
						// We didn't find the boundary. The shift distance is precisely the number
						// of bytes at the start of the buffer that *cannot* match the boundary,
						// which are bytes that can be returned as our output.
						fDataStart = 0;
						fDataEnd = fDistance[fBuffer[boundarySize - 1]];
						}
					}
				}
			}
		if (oCountRead)
			*oCountRead = localDest - reinterpret_cast<uint8*>(oDest);
		}
	}
Beispiel #2
0
void ZStreamRWCon_SSL_Win::Imp_Read(void* oDest, size_t iCount, size_t* oCountRead)
{
    ZAcqMtx acq(fMtx_R);

    char* localDest = static_cast<char*>(oDest);

    while (iCount)
    {
        if (fBufferPlain.size())
        {
            // We've got some data to return.
            size_t countToRead = min(iCount, fBufferPlain.size());
            deque<char>::iterator begin = fBufferPlain.begin();
            deque<char>::iterator end = begin + countToRead;
            std::copy(begin, end, static_cast<char*>(localDest));
            fBufferPlain.erase(begin, end);
            localDest += countToRead;
            iCount -= countToRead;
        }

        if (localDest != oDest)
        {
            // We've somehow managed to read some data, just above or down
            // below, and so can bail from the loop.
            break;
        }

        if (not fReceiveOpen)
            break;

        // We pass four buffers. inSB[0] references the available encrypted
        // data. inSB[1] through inSB[3] are marked as being empty, and may
        // be modified by DecryptMessage.
        SecBuffer inSB[4];
        inSB[0].cbBuffer = fBufferEnc.size();
        inSB[0].pvBuffer = ZUtil_STL::sFirstOrNil(fBufferEnc);
        inSB[0].BufferType = SECBUFFER_DATA;

        inSB[1].BufferType = SECBUFFER_EMPTY;
        inSB[2].BufferType = SECBUFFER_EMPTY;
        inSB[3].BufferType = SECBUFFER_EMPTY;

        SecBufferDesc inSBD;
        inSBD.cBuffers = 4;
        inSBD.pBuffers = inSB;
        inSBD.ulVersion = SECBUFFER_VERSION;

        SECURITY_STATUS scRet = spPSFT->DecryptMessage(&fCtxtHandle, &inSBD, 0, nullptr);

        if (scRet == SEC_E_INCOMPLETE_MESSAGE || (FAILED(scRet) && fBufferEnc.empty()))
        {
            // fBufferEnc holds an incomplete chunk, DecryptMessage needs
            // more data before it can do the decrypt.
            if (not spReadMore(fBufferEnc, fStreamR))
            {
                // We couldn't read any more encrypted data. Mark
                // our receive as being closed.
                fReceiveOpen = false;
            }
            continue;
        }

        if (scRet == SEC_I_CONTEXT_EXPIRED)
        {
            // SSL-level disconnect has been sent by the other side.
            fReceiveOpen = false;
            continue;
        }

        if (scRet == SEC_I_RENEGOTIATE)
        {
            // We need to re-handshake.
            if (not this->pHandshake())
            {
                fReceiveOpen = false;
                fSendOpen = false;
            }
            continue;
        }

        if (FAILED(scRet))
        {
            // We failed for some other reason.
            fReceiveOpen = false;
            continue;
        }

        // If DecryptMessage did any work, inSB[0] through inSB[2] will now reference
        // the header, decrypted data and trailer. inSB[3] will indicate how many
        // bytes at the end of fBufferEnc were unused by this decrypt, and so
        // must be preserved for subsequent use.
        // This assignment of information to buffers is only something I've determined
        // by inspection, so for safety we walk through them to find the two we care
        // about -- the decrypted data and any unused encrypted data.

        SecBuffer* decrypted = nullptr;
        SecBuffer* encrypted = nullptr;

        // Pickup any decrypted data
        for (size_t x = 0; x < 4; ++x)
        {
            if (inSB[x].BufferType == SECBUFFER_DATA && ! decrypted)
                decrypted = &inSB[x];
            if (inSB[x].BufferType == SECBUFFER_EXTRA && ! encrypted)
                encrypted = &inSB[x];
        }

        // The decryption happens in-place, ie in fBufferEnc. Therefore
        // we must copy out the decrypted data before munging fBufferEnc to
        // reference only the unused data.

        if (decrypted)
        {
            // Copy some decrypted data to our destination.
            const size_t countToCopy = std::min(iCount, size_t(decrypted->cbBuffer));
            sMemCopy(localDest, decrypted->pvBuffer, countToCopy);
            localDest += countToCopy;
            iCount -= countToCopy;

            // Anything remaining we put in fBufferPlain, which must be
            // empty otherwise we wouldn't have got to this point.
            const char* data = static_cast<const char*>(decrypted->pvBuffer);
            fBufferPlain.insert(fBufferPlain.begin(),
                                data + countToCopy, data + decrypted->cbBuffer);
        }

        if (encrypted)
        {
            // There is some unused data, move it to the front of fBufferEnc,
            // and resize fBufferEnc to reference only that data.
            sMemMove(&fBufferEnc[0], encrypted->pvBuffer, encrypted->cbBuffer);
            fBufferEnc.resize(encrypted->cbBuffer);
        }
        else
        {
            // There was no unused data.
            fBufferEnc.clear();
        }
    }

    if (oCountRead)
        *oCountRead = localDest - static_cast<char*>(oDest);
}