📄 misc_rw.c
字号:
/****************************************************************************
* *
* Miscellaneous (Non-ASN.1) Read/Write Routines *
* Copyright Peter Gutmann 1992-2007 *
* *
****************************************************************************/
#if defined( INC_ALL )
#include "bn.h" /* bn.h must be included before crypt.h */
#include "crypt.h"
#include "misc_rw.h"
#else
#include "bn/bn.h" /* bn.h must be included before crypt.h */
#include "crypt.h"
#include "misc/misc_rw.h"
#endif /* Compiler-specific includes */
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* Read large integer data */
typedef enum {
LENGTH_NONE, /* No length type */
LENGTH_16U, /* Unsigned int, 16-bit length */
LENGTH_16U_BITS, /* Unsigned int, 16-bit length, length in bits */
LENGTH_32, /* Signed int, 32-bit length */
LENGTH_LAST /* Last possible length type */
} LENGTH_TYPE;
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
static int readInteger( INOUT STREAM *stream,
OUT_BUFFER_OPT( maxLength, \
*integerLength ) void *integer,
OUT_LENGTH_PKC_Z int *integerLength,
IN_LENGTH_PKC const int minLength,
IN_LENGTH_PKC const int maxLength,
IN_ENUM( LENGTH ) const LENGTH_TYPE lengthType,
const BOOLEAN checkShortKey )
{
int length;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( integer == NULL || isWritePtr( integer, maxLength ) );
assert( isWritePtr( integerLength, sizeof( int ) ) );
REQUIRES_S( minLength > 0 && minLength < maxLength && \
maxLength <= CRYPT_MAX_PKCSIZE );
REQUIRES_S( lengthType > LENGTH_NONE && lengthType < LENGTH_LAST );
/* Clear return values */
if( integer != NULL )
memset( integer, 0, min( 16, maxLength ) );
*integerLength = 0;
/* Read the length and make sure that it's within range, with a 2-byte
allowance for extra zero-padding (the exact length will be checked
later after the padding is stripped) */
if( lengthType == LENGTH_16U || lengthType == LENGTH_16U_BITS )
length = readUint16( stream );
else
length = readUint32( stream );
if( cryptStatusError( length ) )
return( length );
if( lengthType == LENGTH_16U_BITS )
length = bitsToBytes( length );
if( checkShortKey )
{
REQUIRES( minLength > bitsToBytes( 256 ) );
/* If the length is below the minimum allowed but still looks at
least vaguely valid, report it as a too-short key rather than a
bad data error */
if( isShortPKCKey( length ) )
return( CRYPT_ERROR_NOSECURE );
}
if( length < minLength || length > maxLength + 2 )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
/* If we're reading a signed integer then the sign bit can't be set
since this would produce a negative value. This differs from the
ASN.1 code, where the incorrect setting of the sign bit is so common
that we always treat integers as unsigned */
if( lengthType == LENGTH_32 && ( sPeek( stream ) & 0x80 ) )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
/* Skip possible leading-zero padding and repeat the length check once
the zero-padding has been adjusted */
while( length > 0 && sPeek( stream ) == 0 )
{
int status;
status = sgetc( stream );
if( cryptStatusError( status ) )
return( status );
length--;
}
if( checkShortKey )
{
/* Repeat the earlier check on the adjusted value */
if( isShortPKCKey( length ) )
return( CRYPT_ERROR_NOSECURE );
}
if( length < minLength || length > maxLength )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
/* Read the value */
*integerLength = length;
if( integer == NULL )
return( sSkip( stream, length ) );
return( sread( stream, integer, length ) );
}
/****************************************************************************
* *
* Data Read Routines *
* *
****************************************************************************/
/* Read 16-, 32-, and 64-bit integer values */
RETVAL_RANGE( MAX_ERROR, 0xFFFF ) STDC_NONNULL_ARG( ( 1 ) ) \
int readUint16( INOUT STREAM *stream )
{
BYTE buffer[ UINT16_SIZE + 8 ];
int value, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
status = sread( stream, buffer, UINT16_SIZE );
if( cryptStatusError( status ) )
return( status );
value = ( ( int ) buffer[ 0 ] << 8 ) | buffer[ 1 ];
if( value < 0 || value > 0xFFFFL )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
return( value );
}
RETVAL_RANGE( MAX_ERROR, MAX_INTLENGTH ) STDC_NONNULL_ARG( ( 1 ) ) \
int readUint32( INOUT STREAM *stream )
{
BYTE buffer[ UINT32_SIZE + 8 ];
int value, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
status = sread( stream, buffer, UINT32_SIZE );
if( cryptStatusError( status ) )
return( status );
if( buffer[ 0 ] & 0x80 )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
value = ( ( int ) buffer[ 0 ] << 24 ) | \
( ( int ) buffer[ 1 ] << 16 ) | \
( ( int ) buffer[ 2 ] << 8 ) | \
buffer[ 3 ];
if( value < 0 || value >= MAX_INTLENGTH )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
return( value );
}
RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int readUint64( INOUT STREAM *stream, OUT_INT_Z long *value )
{
BYTE buffer[ ( UINT64_SIZE / 2 ) + 8 ];
int localValue, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( value, sizeof( long ) ) );
/* Clear return value */
*value = 0;
status = sread( stream, buffer, UINT64_SIZE / 2 );
if( cryptStatusError( status ) )
return( status );
if( memcmp( buffer, "\x00\x00\x00\x00", UINT64_SIZE / 2 ) )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
status = localValue = readUint32( stream );
if( cryptStatusError( status ) )
return( status );
*value = localValue;
return( CRYPT_OK );
}
/* Read 32- and 64-bit time values. Note that we can't just call down
directly to readUint32() for these since time_t may be unsigned or of a
different integral size than int. In addition we have to be careful
about the sanity check in readUint32() against MAX_INTLENGTH, which
equates to the value 0x7EFFFFFF ~= mid-2037, so that dates after this
point will fail the range check. However this is only six months before
the hard limit of 2038 anyway, and hopefully by this time we'll be using
64-bit time_t's and won't have to worry about this range limit any
more */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readTime( INOUT STREAM *stream, OUT time_t *timeVal,
const BOOLEAN is64bit )
{
int value = DUMMY_INIT, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( timeVal, sizeof( time_t ) ) );
/* Clear return value */
*timeVal = 0;
if( is64bit )
{
long longValue;
status = readUint64( stream, &longValue );
if( cryptStatusOK( status ) )
value = ( int ) longValue;
}
else
status = value = readUint32( stream );
if( cryptStatusError( status ) )
return( status );
if( value < MIN_STORED_TIME_VALUE )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
*timeVal = ( time_t ) value;
return( CRYPT_OK );
}
RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int readUint32Time( INOUT STREAM *stream, OUT time_t *timeVal )
{
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( timeVal, sizeof( time_t ) ) );
/* Clear return value */
*timeVal = 0;
return( readTime( stream, timeVal, FALSE ) );
}
RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int readUint64Time( INOUT STREAM *stream, OUT time_t *timeVal )
{
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( timeVal, sizeof( time_t ) ) );
/* Clear return value */
*timeVal = 0;
return( readTime( stream, timeVal, TRUE ) );
}
/* Read a string preceded by a 32-bit length */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
static int readData32( INOUT STREAM *stream,
OUT_BUFFER( dataMaxLength, *dataLength ) void *data,
IN_LENGTH_SHORT const int dataMaxLength,
OUT_LENGTH_SHORT_Z int *dataLength,
const BOOLEAN includeLengthField )
{
BYTE *dataPtr = data;
const int headerSize = includeLengthField ? UINT32_SIZE : 0;
int length;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( data, dataMaxLength ) );
assert( isWritePtr( dataLength, sizeof( int ) ) );
REQUIRES_S( dataMaxLength > 0 && dataMaxLength < MAX_INTLENGTH_SHORT );
/* Clear return values */
memset( data, 0, min( 16, dataMaxLength ) );
*dataLength = 0;
length = readUint32( stream );
if( length <= 0 )
{
/* Error or zero length. If it's zero length we don't return any
data */
return( length );
}
if( headerSize + length > dataMaxLength || length > MAX_INTLENGTH_SHORT )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
if( includeLengthField )
{
dataPtr[ 0 ] = ( length >> 24 ) & 0xFF;
dataPtr[ 1 ] = ( length >> 16 ) & 0xFF;
dataPtr[ 2 ] = ( length >> 8 ) & 0xFF;
dataPtr[ 3 ] = length & 0xFF;
}
*dataLength = headerSize + length;
return( sread( stream, dataPtr + headerSize, length ) );
}
RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
int readString32( INOUT STREAM *stream,
OUT_BUFFER( stringMaxLength, \
*stringLength ) void *string,
IN_LENGTH_SHORT const int stringMaxLength,
OUT_LENGTH_SHORT_Z int *stringLength )
{
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( string, stringMaxLength ) && \
isWritePtr( stringLength, sizeof( int ) ) );
REQUIRES_S( stringMaxLength > 0 && stringMaxLength < MAX_INTLENGTH_SHORT );
/* Read the string, limiting the size to the maximum buffer size */
return( readData32( stream, string, stringMaxLength, stringLength, FALSE ) );
}
/* Read a raw object preceded by a 32-bit length */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
int readRawObject32( INOUT STREAM *stream,
OUT_BUFFER( bufferMaxLength, bufferLength ) void *buffer,
IN_LENGTH_SHORT_MIN( UINT32_SIZE + 1 ) \
const int bufferMaxLength,
OUT_LENGTH_SHORT_Z int *bufferLength )
{
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( buffer, bufferMaxLength ) &&
isWritePtr( bufferLength, sizeof( int ) ) );
REQUIRES_S( bufferMaxLength >= UINT32_SIZE + 1 && \
bufferMaxLength < MAX_INTLENGTH_SHORT );
/* Read the string, limiting the size to the maximum buffer size */
return( readData32( stream, buffer, bufferMaxLength, bufferLength,
TRUE ) );
}
/* Read a universal type and discard it, used to skip unknown or unwanted
types */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int readUniversal( INOUT STREAM *stream,
IN_ENUM( LENGTH ) const LENGTH_TYPE lengthType )
{
int length;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
REQUIRES_S( lengthType == LENGTH_16U || lengthType == LENGTH_32 );
/* Read the length and skip the data */
if( lengthType == LENGTH_16U )
length = readUint16( stream );
else
length = readUint32( stream );
if( length <= 0 )
{
/* Error or zero length */
return( length );
}
return( sSkip( stream, length ) );
}
RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int readUniversal16( INOUT STREAM *stream )
{
return( readUniversal( stream, LENGTH_16U ) );
}
RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int readUniversal32( INOUT STREAM *stream )
{
return( readUniversal( stream, LENGTH_32 ) );
}
/* Read (large) integers in various formats */
RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
int readInteger16U( INOUT STREAM *stream,
OUT_BUFFER_OPT( maxLength, \
*integerLength ) void *integer,
OUT_LENGTH_PKC_Z int *integerLength,
IN_LENGTH_PKC const int minLength,
IN_LENGTH_PKC const int maxLength )
{
return( readInteger( stream, integer, integerLength, minLength,
maxLength, LENGTH_16U, FALSE ) );
}
RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
int readInteger16Ubits( INOUT STREAM *stream,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -