📄 env_dec.c
字号:
assert( NOTREACHED );
return( CRYPT_ERROR_BADDATA );
}
assert( length > 0 );
assert( isReadPtr( buffer, 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 out-of-band data from a lookahead read present,
insert it into the output stream */
if( envelopeInfoPtr->oobBufPos > 0 )
{
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 <= 0 )
return( oobBytesCopied );
}
/* If we're using compression, expand the data from the buffer to the
output via the zStream */
#ifdef USE_COMPRESSION
if( envelopeInfoPtr->flags & ENVELOPE_ZSTREAMINITED )
{
const int bytesIn = \
( envelopeInfoPtr->dataLeft > 0 && \
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 that 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 && \
envelopeInfoPtr->type == CRYPT_FORMAT_PGP ) )
{
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 of the 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 <= 0 && \
envelopeInfoPtr->dataLeft > 0 && \
envelopeInfoPtr->dataLeft < envelopeInfoPtr->bufPos )
{
if( envelopeInfoPtr->type != CRYPT_FORMAT_PGP && \
( !( envelopeInfoPtr->dataFlags & ENVDATA_ENDOFCONTENTS ) || \
( envelopeInfoPtr->bufPos - envelopeInfoPtr->dataLeft != 2 ) ) )
{
/* We should only have the EOC octets present at this
point */
assert( NOTREACHED );
return( CRYPT_ERROR_BADDATA );
}
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 /* USE_COMPRESSION */
{
ACTION_LIST *hashActionPtr;
/* Copy out as much of the data as we can, making sure that we don't
overrun into any following data */
if( bytesToCopy > envelopeInfoPtr->bufPos )
bytesToCopy = envelopeInfoPtr->bufPos;
if( envelopeInfoPtr->dataLeft > 0 && \
bytesToCopy > envelopeInfoPtr->dataLeft )
bytesToCopy = envelopeInfoPtr->dataLeft;
if( bytesToCopy < 0 )
{
/* Safety check */
assert( NOTREACHED );
return( CRYPT_ERROR_BADDATA );
}
/* 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->dataFlags & ENVDATA_ENDOFCONTENTS ) && \
envelopeInfoPtr->blockBufferPos > 0 )
{
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 (e.g.
due to blocking requirements), exit */
if( ( ( envelopeInfoPtr->dataFlags & ENVDATA_ENDOFCONTENTS ) && \
envelopeInfoPtr->dataLeft <= 0 ) || \
bytesToCopy <= 0 )
return( oobBytesCopied );
assert( bytesToCopy > 0 );
/* 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 complete the hashing */
if( envelopeInfoPtr->dataFlags & ENVDATA_HASHACTIONSACTIVE )
for( hashActionPtr = envelopeInfoPtr->actionList;
hashActionPtr != NULL && hashActionPtr->action == ACTION_HASH;
hashActionPtr = hashActionPtr->next )
krnlSendMessage( hashActionPtr->iCryptHandle,
IMESSAGE_CTX_HASH, bufPtr, bytesToCopy );
/* We're not using compression, copy the data across directly */
memcpy( buffer, bufPtr, bytesToCopy );
bytesCopied = bytesToCopy;
}
/* Safety check */
if( envelopeInfoPtr->bufPos - bytesCopied < 0 )
{
assert( NOTREACHED );
return( CRYPT_ERROR_BADDATA );
}
/* Move any remaining data down to the start of the buffer */
remainder = envelopeInfoPtr->bufPos - bytesCopied;
if( remainder > 0 && bytesCopied > 0 )
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 that we've just copied out */
if( envelopeInfoPtr->dataLeft > 0 && bytesCopied > 0 )
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 = 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 that 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
since we're using memmove this shouldn't be a problem.
Since we're in effect restarting from the payload data, we reset
everything that 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 <= 0 )
{
/* 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->copyToEnvelopeFunction( 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 );
}
assert( bytesCopied >= 0 );
/* If we've reached the end of the payload, remember where the payload
ends. If there's anything that 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->dataFlags & ENVDATA_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 that 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->dataFlags & ENVDATA_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 we're
given a null buffer we substitute an empty (non-null) one */
if( buffer == NULL )
buffer = "";
/* Hash the data or wrap up the hashing as appropriate */
for( hashActionPtr = envelopeInfoPtr->actionList;
hashActionPtr != NULL && hashActionPtr->action == ACTION_HASH;
hashActionPtr = hashActionPtr->next )
{
status = krnlSendMessage( hashActionPtr->iCryptHandle,
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 <= 0 )
envelopeInfoPtr->dataFlags &= ~ENVDATA_HASHACTIONSACTIVE;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Envelope Access Routines *
* *
****************************************************************************/
void initDeenvelopeStreaming( ENVELOPE_INFO *envelopeInfoPtr )
{
/* Set the access method pointers */
envelopeInfoPtr->copyToEnvelopeFunction = copyToDeenvelope;
envelopeInfoPtr->copyFromEnvelopeFunction = copyFromDeenvelope;
envelopeInfoPtr->syncDeenvelopeData = syncDeenvelopeData;
envelopeInfoPtr->processExtraData = processExtraData;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -