📄 decode.c
字号:
{
ENSURES( status != Z_STREAM_ERROR ); /* Parameter error */
return( ( status == Z_DATA_ERROR ) ? CRYPT_ERROR_BADDATA : \
( status == Z_MEM_ERROR ) ? CRYPT_ERROR_MEMORY : \
( status == Z_BUF_ERROR ) ? CRYPT_ERROR_UNDERFLOW : \
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 -= envelopeInfoPtr->zStream.avail_out;
ENSURES( bytesCopied >= 0 && bytesCopied < MAX_INTLENGTH && \
bytesToCopy >= 0 && bytesToCopy <= originalInLength && \
bytesToCopy < MAX_INTLENGTH );
#if 0 /* 7/6/07 This check doesn't seem to serve any useful purpose since
EOCs are handled at a higher level. In particular the check for
a single pair of EOCs produces false positives when there's a
string of EOCs present at the end of the data. This code goes
back to at least 3.0 while the EOC handling has changed a fair
bit since then so it's likely that it's an artefact from much
older code */
/* 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 { 0x00 0x00 } present
at this point */
retIntError();
}
envelopeInfoPtr->dataLeft = envelopeInfoPtr->bufPos;
}
#endif /* 0 */
/* If we're doing a lookahead read we can't just copy the data out
of the envelope buffer as we would for any other content type
because we can't undo the decompression step, so we copy the data
that was decompressed into the output buffer to a local buffer
and insert it into the output stream on the next non-lookahead
read. The size of the read from the OOB buffer has been limited
previously when existing data was detected in the OOB buffer so
the total of the current OOB buffer contents and the amount to
read can never exceed the OOB buffer size */
if( isLookaheadRead )
{
REQUIRES( envelopeInfoPtr->oobBufPos + \
originalInLength <= OOB_BUFFER_SIZE );
memcpy( envelopeInfoPtr->oobBuffer + envelopeInfoPtr->oobBufPos,
buffer, originalInLength );
envelopeInfoPtr->oobBufPos += originalInLength;
}
}
else
#endif /* USE_COMPRESSION */
{
/* 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;
ENSURES( bytesToCopy >= 0 && bytesToCopy <= maxLength && \
bytesToCopy < MAX_INTLENGTH );
/* We perform the postcondition check here because there are
numerous exit points in the following code and this avoids having
to check at every one */
ENSURES( sanityCheck( envelopeInfoPtr ) );
/* 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,
so we decrease the effective data amount by one block's worth */
if( envelopeInfoPtr->blockSize > 1 && \
!( envelopeInfoPtr->dataFlags & ENVDATA_ENDOFCONTENTS ) && \
envelopeInfoPtr->blockBufferPos > 0 )
bytesToCopy -= envelopeInfoPtr->blockSize;
/* If we've ended up with nothing to copy (e.g. due to blocking
requirements), exit */
if( bytesToCopy <= 0 )
{
*length = oobBytesCopied;
return( CRYPT_OK );
}
ENSURES( bytesToCopy > 0 && bytesToCopy < MAX_INTLENGTH );
/* If we've seen the end-of-contents octets and there's no payload
left to copy out, exit */
if( ( envelopeInfoPtr->dataFlags & ENVDATA_ENDOFCONTENTS ) && \
envelopeInfoPtr->dataLeft <= 0 )
{
*length = oobBytesCopied;
return( CRYPT_OK );
}
/* If we're doing a lookahead read just copy the data out without
adjusting the read-data values */
if( isLookaheadRead )
{
REQUIRES( bytesToCopy > 0 && bytesToCopy <= OOB_BUFFER_SIZE );
memcpy( buffer, envelopeInfoPtr->buffer, bytesToCopy );
*length = bytesToCopy;
return( CRYPT_OK );
}
/* Hash the payload data if necessary */
if( envelopeInfoPtr->dataFlags & ENVDATA_HASHACTIONSACTIVE )
{
status = hashEnvelopeData( envelopeInfoPtr->actionList,
envelopeInfoPtr->buffer,
bytesToCopy );
if( cryptStatusError( status ) )
return( status );
}
/* We're not using compression, copy the data across directly */
memcpy( buffer, envelopeInfoPtr->buffer, bytesToCopy );
bytesCopied = bytesToCopy;
}
ENSURES( envelopeInfoPtr->bufPos - bytesCopied >= 0 );
/* Move any remaining data down to the start of the buffer */
remainder = envelopeInfoPtr->bufPos - bytesCopied;
ENSURES( remainder >= 0 && remainder < MAX_INTLENGTH && \
bytesCopied >= 0 && bytesCopied < MAX_INTLENGTH && \
bytesCopied + remainder <= envelopeInfoPtr->bufSize );
if( remainder > 0 && bytesCopied > 0 )
{
memmove( envelopeInfoPtr->buffer,
envelopeInfoPtr->buffer + 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;
ENSURES( envelopeInfoPtr->dataLeft >= 0 && \
envelopeInfoPtr->dataLeft < MAX_INTLENGTH );
*length = oobBytesCopied + bytesToCopy;
ENSURES( sanityCheck( envelopeInfoPtr ) );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Extra Data Management Functions *
* *
****************************************************************************/
/* Synchronise the deenveloping data stream */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int syncDeenvelopeData( INOUT ENVELOPE_INFO *envelopeInfoPtr,
INOUT STREAM *stream )
{
const long dataStartPos = stell( stream );
const int oldBufPos = envelopeInfoPtr->bufPos;
const int bytesLeft = sMemDataLeft( stream );
int bytesCopied;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( isWritePtr( stream, sizeof( STREAM ) ) );
/*///////////////////////////////////////////////////*/
assert( envelopeInfoPtr->segmentSize != CRYPT_UNUSED );
/*///////////////////////////////////////////////////*/
REQUIRES( sanityCheck( envelopeInfoPtr ) );
REQUIRES( !cryptStatusError( dataStartPos ) );
/* 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/CMS short definite-length
OCTET STRING) we only consume two bytes, the tag and one-byte length,
but since we're using memmove() in copyData() 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(), and
if the data is corrupted we won't be able to get any further
anyway */
envelopeInfoPtr->bufPos = oldBufPos;
ENSURES( sanityCheck( envelopeInfoPtr ) );
return( bytesCopied );
}
ENSURES( bytesCopied >= 0 && bytesCopied < MAX_INTLENGTH );
/* If we copied over less than the total available and have hit the
end-of-data marker it means that there's extra data following the
payload. We need to move this down to the end of the decoded payload
data since copyToDeenvelope() stops copying as soon as it hits the
end-of-data. We use memmove() rather than memcpy() for this since
we're copying to/from the same buffer:
dataStartPos
|
v<--- bLeft --->|
+---------------+---------------+--------
| |///////////////| Start
+---------------+---------------+--------
dataStartPos
|
|<- bCop -->| v |<-bToC>|
+---------------+---------------+--------
|//payload//| | |///////| After copyToDeenvelope
+---------------+---------------+--------
^ ^
| |
dataLeft dStartPos + bCopied
+-----------+-------+--------------------
|//payload//|///////| EOC
+-----------+-------+--------------------
^ ^
| |
dLeft bufPos */
if( ( envelopeInfoPtr->dataFlags & ENVDATA_ENDOFCONTENTS ) && \
bytesCopied < bytesLeft )
{
const int bytesToCopy = bytesLeft - bytesCopied;
REQUIRES( bytesToCopy > 0 && bytesToCopy < MAX_INTLENGTH && \
envelopeInfoPtr->dataLeft + \
bytesToCopy <= envelopeInfoPtr->bufSize && \
bytesCopied + dataStartPos + \
bytesToCopy <= envelopeInfoPtr->bufSize );
memmove( envelopeInfoPtr->buffer + envelopeInfoPtr->dataLeft,
envelopeInfoPtr->buffer + dataStartPos + bytesCopied,
bytesToCopy );
envelopeInfoPtr->bufPos = envelopeInfoPtr->dataLeft + bytesToCopy;
}
ENSURES( sanityCheck( envelopeInfoPtr ) );
return( CRYPT_OK );
}
/* Process additional out-of-band data that doesn't get copied into/out of
the de-enveloping envelope */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int processExtraData( INOUT ENVELOPE_INFO *envelopeInfoPtr,
IN_BUFFER( length ) const void *buffer,
IN_LENGTH const int length )
{
int status;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( length == 0 || isReadPtr( buffer, length ) );
REQUIRES( sanityCheck( envelopeInfoPtr ) );
REQUIRES( length >= 0 && length < MAX_INTLENGTH );
/* If the hash value was supplied externally (which means that 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 > 0 ) ? CRYPT_ERROR_BADDATA : CRYPT_OK );
/* Hash the data or wrap up the hashing as appropriate */
status = hashEnvelopeData( envelopeInfoPtr->actionList, 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 *
* *
****************************************************************************/
STDC_NONNULL_ARG( ( 1 ) ) \
void initDeenvelopeStreaming( INOUT ENVELOPE_INFO *envelopeInfoPtr )
{
/* Set the access method pointers */
envelopeInfoPtr->copyToEnvelopeFunction = copyToDeenvelope;
envelopeInfoPtr->copyFromEnvelopeFunction = copyFromDeenvelope;
envelopeInfoPtr->syncDeenvelopeData = syncDeenvelopeData;
envelopeInfoPtr->processExtraData = processExtraData;
}
#endif /* USE_ENVELOPES */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -