📄 octetstr.c
字号:
{
status = getNextSegment( envelopeInfoPtr, bufPtr, length );
if( cryptStatusError( status ) )
return( status );
bufPtr += status;
length -= status;
if( envelopeInfoPtr->endOfContents || !length )
break; /* EOC reached or all data consumed, exit */
}
/* Copy the (possibly encrypted) data into the envelope */
bytesCopied = copyData( envelopeInfoPtr, bufPtr, length );
if( cryptStatusError( bytesCopied ) )
return( bytesCopied );
bufPtr += bytesCopied;
length -= bytesCopied;
assert( envelopeInfoPtr->bufPos <= envelopeInfoPtr->bufSize );
assert( length >= 0 );
assert( ( envelopeInfoPtr->segmentSize >= 0 ) || \
( ( envelopeInfoPtr->flags & ENVELOPE_NOSEGMENT ) && \
( envelopeInfoPtr->payloadSize == CRYPT_UNUSED ) && \
( envelopeInfoPtr->segmentSize == CRYPT_UNUSED ) ) );
}
while( length > 0 && bytesCopied );
return( oldLength - length );
}
/* Copy data from the de-enveloping envelope. Returns the number of bytes
copied */
static int copyFromDeenvelope( ENVELOPE_INFO *envelopeInfoPtr, BYTE *buffer,
int length )
{
BYTE *bufPtr = envelopeInfoPtr->buffer;
const BOOLEAN isLookaheadRead = ( length < 0 ) ? TRUE : FALSE;
int bytesToCopy, bytesCopied, remainder;
int oobBytesCopied = 0;
/* Remember how much data we need to copy */
bytesToCopy = length = ( length < 0 ) ? -length : length;
/* If we're verifying a detached sig, the data is communicated out-of-
band so there's nothing to copy out */
if( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG )
return( 0 );
/* If there's buffered data from a lookahead read present, insert it into
the output stream */
if( envelopeInfoPtr->oobBufPos )
{
oobBytesCopied = min( bytesToCopy, envelopeInfoPtr->oobBufPos );
memcpy( buffer, envelopeInfoPtr->oobBuffer, oobBytesCopied );
if( !isLookaheadRead )
{
/* If we moved the data out of the OOB buffer, adjust the OOB
buffer contents */
if( envelopeInfoPtr->oobBufPos > oobBytesCopied )
memmove( envelopeInfoPtr->oobBuffer,
envelopeInfoPtr->oobBuffer + oobBytesCopied,
envelopeInfoPtr->oobBufPos - oobBytesCopied );
envelopeInfoPtr->oobBufPos -= oobBytesCopied;
}
bytesToCopy -= oobBytesCopied;
length -= oobBytesCopied;
buffer += oobBytesCopied;
if( !bytesToCopy )
return( oobBytesCopied );
}
/* If we're using compression, expand the data from the buffer to the
output via the zStream */
#ifndef NO_COMPRESSION
if( envelopeInfoPtr->zStreamInited )
{
const int bytesIn = \
( envelopeInfoPtr->dataLeft && \
envelopeInfoPtr->dataLeft < envelopeInfoPtr->bufPos ) ? \
envelopeInfoPtr->dataLeft : envelopeInfoPtr->bufPos;
int status;
/* Decompress the data into the output buffer. Note that we use the
length value to determine the length of the output rather than
bytesToCopy since the ratio of bytes in the buffer to bytes of
output isn't 1:1 as it is for other content types.
When using PGP 2.x-compatible decompression, we have to allow a
return status of Z_BUF_ERROR because it uses a compression format
from a pre-release version of InfoZip which doesn't include
header or trailer information, so the decompression code can't
definitely tell that it's reached the end of its input data but
can only report that it can't go any further */
envelopeInfoPtr->zStream.next_in = bufPtr;
envelopeInfoPtr->zStream.avail_in = bytesIn;
envelopeInfoPtr->zStream.next_out = buffer;
envelopeInfoPtr->zStream.avail_out = length;
status = inflate( &envelopeInfoPtr->zStream, Z_SYNC_FLUSH );
if( status != Z_OK && status != Z_STREAM_END && \
status != Z_BUF_ERROR )
{
assert( status != Z_STREAM_ERROR ); /* Parameter error */
return( ( status == Z_DATA_ERROR ) ? CRYPT_ERROR_BADDATA : \
( status == Z_MEM_ERROR ) ? CRYPT_ERROR_MEMORY : \
CRYPT_ERROR_FAILED );
}
/* Adjust the status information based on the data copied from the
buffer into the zStream (bytesCopied) and the data flushed from
the zStream to the output (bytesToCopy) */
bytesCopied = bytesIn - envelopeInfoPtr->zStream.avail_in;
bytesToCopy = length - envelopeInfoPtr->zStream.avail_out;
assert( bytesCopied >= 0 && bytesToCopy >= 0 );
/* If we consumed all input and there's extra data left after
the end of the data stream, it's EOC information, mark that
as consumed as well */
if( !envelopeInfoPtr->zStream.avail_in && \
envelopeInfoPtr->dataLeft && \
envelopeInfoPtr->dataLeft < envelopeInfoPtr->bufPos )
{
assert( ( envelopeInfoPtr->type == CRYPT_FORMAT_PGP ) || \
( envelopeInfoPtr->endOfContents && \
( envelopeInfoPtr->bufPos - \
envelopeInfoPtr->dataLeft == 2 ) ) );
envelopeInfoPtr->dataLeft = envelopeInfoPtr->bufPos;
}
/* If we're doing a lookahead read, we can't just copy the data out
as we would for any other content type because we can't undo the
decompression step, so we remember the output data in a local
buffer and insert it into the output stream on the next read */
if( isLookaheadRead )
{
assert( envelopeInfoPtr->oobBufPos + length <= OOB_BUFFER_SIZE );
memcpy( envelopeInfoPtr->oobBuffer + envelopeInfoPtr->oobBufPos,
buffer, length );
envelopeInfoPtr->oobBufPos += length;
}
}
else
#endif /* NO_COMPRESSION */
{
ACTION_LIST *hashActionPtr;
/* Copy out as much of the data as we can, making sure we don't
overrun into any following data */
if( bytesToCopy > envelopeInfoPtr->bufPos )
bytesToCopy = envelopeInfoPtr->bufPos;
if( envelopeInfoPtr->dataLeft && \
bytesToCopy > envelopeInfoPtr->dataLeft )
bytesToCopy = envelopeInfoPtr->dataLeft;
/* If we're using a block encryption mode and we haven't seen the
end-of-contents yet and there's no data waiting in the block
buffer (which would mean that there's more data to come), we
can't copy out the last block because it might contain padding */
if( envelopeInfoPtr->blockSize > 1 && \
!envelopeInfoPtr->endOfContents && \
!envelopeInfoPtr->blockBufferPos )
{
bytesToCopy -= envelopeInfoPtr->blockSize;
if( bytesToCopy <= 0 )
return( 0 );
}
/* If we've seen the end-of-contents octets and there's no payload
left to copy out, or if we've ended up with nothing to copy (eg
due to blocking requirements), exit */
if( ( envelopeInfoPtr->endOfContents && !envelopeInfoPtr->dataLeft ) || \
!bytesToCopy )
return( oobBytesCopied );
/* If we're doing a lookahead read, just copy the data out without
adjusting the read-data values */
if( isLookaheadRead )
{
memcpy( buffer, bufPtr, bytesToCopy );
return( bytesToCopy );
}
/* Hash the payload data if necessary. We don't have to check for
problems with the context at this point since they'll be detected
when we try and read the hash value */
if( envelopeInfoPtr->hashActionsActive )
for( hashActionPtr = envelopeInfoPtr->actionList;
hashActionPtr != NULL; hashActionPtr = hashActionPtr->next )
krnlSendMessage( hashActionPtr->iCryptHandle,
RESOURCE_IMESSAGE_CTX_HASH, bufPtr,
bytesToCopy );
/* We're not using compression, copy the data across directly */
memcpy( buffer, bufPtr, bytesToCopy );
bytesCopied = bytesToCopy;
}
/* Move any remaining data down to the start of the buffer */
remainder = envelopeInfoPtr->bufPos - bytesCopied;
assert( remainder >= 0 );
if( remainder && bytesCopied )
memmove( bufPtr, bufPtr + bytesCopied, remainder );
envelopeInfoPtr->bufPos = remainder;
/* If there's data following the payload, adjust the end-of-payload
pointer to reflect the data we've just copied out */
if( envelopeInfoPtr->dataLeft )
envelopeInfoPtr->dataLeft -= bytesCopied;
assert( envelopeInfoPtr->dataLeft >= 0 );
return( oobBytesCopied + bytesToCopy );
}
/* Synchronise the deenveloping data stream */
static int syncDeenvelopeData( ENVELOPE_INFO *envelopeInfoPtr,
STREAM *stream )
{
const int dataStartPos = ( int ) stell( stream );
const int oldBufPos = envelopeInfoPtr->bufPos;
const int bytesLeft = sMemDataLeft( stream );
int bytesCopied;
/* After the envelope header has been processed, what's left is payload
data which requires special processing because of segmenting and
decryption and hashing requirements, so we feed it in via a
copyToDeenvelope() of the data in the buffer. This is a rather ugly
hack, but it works because we're moving data backwards in the buffer
so there shouldn't be any problems for the rare instances where the
data overlaps (in the worst case (PKCS #7 short definite-length OCTET
STRING) we only consume two bytes, the tag and one-byte length, but
for any normal memcpy() which moves forwards through memory this
shouldn't be a problem).
Since we're in effect restarting from the payload data, we reset
everything which counts to point back to the start of the buffer where
we'll be moving the payload data. We don't have to worry about the
copyToDeenvelope() overflowing the envelope since the source is the
envelope buffer so the data must fit within the envelope */
envelopeInfoPtr->bufPos = 0;
if( !bytesLeft )
{
/* Handle the special case of the data ending at exactly this point */
sseek( stream, 0 );
return( CRYPT_ERROR_UNDERFLOW );
}
sMemDisconnect( stream );
sMemConnect( stream, envelopeInfoPtr->buffer, bytesLeft );
bytesCopied = envelopeInfoPtr->copyToDeenvelope( envelopeInfoPtr,
envelopeInfoPtr->buffer + dataStartPos, bytesLeft );
if( cryptStatusError( bytesCopied ) )
{
/* Undo the buffer position reset. This isn't 100% effective if
there are multiple segments present and we hit an error after
we've copied down enough data to overwrite what's at the start,
but in most cases it allows us to undo the copyToEnvelope() - if
the data is corrupted we won't get any further anyway */
envelopeInfoPtr->bufPos = oldBufPos;
return( bytesCopied );
}
/* If we've reached the end of the payload, remember where the payload
ends. If there's anything which followed the payload, we need to move
it down to the end of the decoded payload data, since
copyToDeenvelope() stops copying as soon as it hits the end-of-
contents octets */
if( envelopeInfoPtr->endOfContents && bytesCopied < bytesLeft )
{
const int bytesToCopy = bytesLeft - bytesCopied;
memcpy( envelopeInfoPtr->buffer + envelopeInfoPtr->dataLeft,
envelopeInfoPtr->buffer + bytesCopied + dataStartPos,
bytesToCopy );
envelopeInfoPtr->bufPos = envelopeInfoPtr->dataLeft + bytesToCopy;
}
return( CRYPT_OK );
}
/* Process additional out-of-band data which doesn't get copied into/out of
the de-enveloping envelope */
static int processExtraData( ENVELOPE_INFO *envelopeInfoPtr,
const void *buffer, const int length )
{
ACTION_LIST *hashActionPtr;
int status;
/* If the hash value was supplied externally (which means there's
nothing for us to hash, since it's already been done by the caller),
there won't be any hash actions active and we can return immediately */
if( !envelopeInfoPtr->hashActionsActive )
return( length ? CRYPT_ERROR_BADDATA : CRYPT_OK );
/* The enveloping code uses a null buffer to signify a flush, but the
lower-level encryption actions don't allow a null buffer */
if( buffer == NULL )
buffer = "";
/* Hash the data or wrap up the hashing as appropriate */
for( hashActionPtr = envelopeInfoPtr->actionList;
hashActionPtr != NULL; hashActionPtr = hashActionPtr->next )
{
status = krnlSendMessage( hashActionPtr->iCryptHandle,
RESOURCE_IMESSAGE_CTX_HASH,
( void * ) buffer, length );
if( cryptStatusError( status ) )
return( status );
}
/* If we've finished the hashing, clear the hashing active flag to
prevent data from being hashed again if it's processed by other
code such as copyFromDeenvelope() */
if( !length )
envelopeInfoPtr->hashActionsActive = FALSE;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Envelope Access Routines *
* *
****************************************************************************/
void initDataStreaming( ENVELOPE_INFO *envelopeInfoPtr )
{
/* Set the access method pointers */
envelopeInfoPtr->copyToEnvelope = copyToEnvelope;
envelopeInfoPtr->copyFromEnvelope = copyFromEnvelope;
envelopeInfoPtr->copyToDeenvelope = copyToDeenvelope;
envelopeInfoPtr->copyFromDeenvelope = copyFromDeenvelope;
envelopeInfoPtr->syncDeenvelopeData = syncDeenvelopeData;
envelopeInfoPtr->processExtraData = processExtraData;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -