📄 int_api.c
字号:
int envelopeUnwrap( const void *inData, const int inDataLength,
void *outData, int *outDataLength,
const int outDataMaxLength,
const CRYPT_CONTEXT iDecryptKey )
{
CRYPT_ENVELOPE iCryptEnvelope;
MESSAGE_CREATEOBJECT_INFO createInfo;
RESOURCE_DATA msgData;
const int minBufferSize = max( MIN_BUFFER_SIZE, inDataLength );
int status;
assert( isReadPtr( inData, inDataLength ) );
assert( inDataLength > 16 );
assert( isWritePtr( outData, outDataMaxLength ) );
assert( outDataMaxLength > 16 );
assert( isWritePtr( outDataLength, sizeof( int ) ) );
assert( ( iDecryptKey == CRYPT_UNUSED ) || \
isHandleRangeValid( iDecryptKey ) );
*outDataLength = 0;
/* Create an envelope to unwrap the data, add the decryption key if
necessary, and pop the unwrapped result */
setMessageCreateObjectInfo( &createInfo, CRYPT_FORMAT_AUTO );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_ENVELOPE );
if( cryptStatusError( status ) )
return( status );
iCryptEnvelope = createInfo.cryptHandle;
krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
( void * ) &minBufferSize, CRYPT_ATTRIBUTE_BUFFERSIZE );
setMessageData( &msgData, ( void * ) inData, inDataLength );
status = krnlSendMessage( iCryptEnvelope, IMESSAGE_ENV_PUSHDATA,
&msgData, 0 );
if( status == CRYPT_ENVELOPE_RESOURCE )
{
/* If the caller wasn't expecting encrypted data, let them know */
if( iDecryptKey == CRYPT_UNUSED )
status = CRYPT_ERROR_WRONGKEY;
else
status = krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
( void * ) &iDecryptKey,
CRYPT_ENVINFO_PRIVATEKEY );
}
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( iCryptEnvelope, IMESSAGE_ENV_PUSHDATA,
&msgData, 0 );
}
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, outData, outDataMaxLength );
status = krnlSendMessage( iCryptEnvelope, IMESSAGE_ENV_POPDATA,
&msgData, 0 );
}
krnlSendNotifier( iCryptEnvelope, IMESSAGE_DECREFCOUNT );
if( cryptStatusOK( status ) )
*outDataLength = msgData.length;
return( status );
}
int envelopeSign( const void *inData, const int inDataLength,
void *outData, int *outDataLength,
const int outDataMaxLength,
const CRYPT_CONTENT_TYPE contentType,
const CRYPT_CONTEXT iSigKey,
const CRYPT_CERTIFICATE iCmsAttributes )
{
CRYPT_ENVELOPE iCryptEnvelope;
MESSAGE_CREATEOBJECT_INFO createInfo;
RESOURCE_DATA msgData;
const int minBufferSize = max( MIN_BUFFER_SIZE, inDataLength + 1024 );
int status;
assert( isReadPtr( inData, inDataLength ) );
assert( inDataLength > 16 || \
( contentType == CRYPT_CONTENT_NONE && \
isHandleRangeValid( iCmsAttributes ) && \
inDataLength == 0 ) );
assert( isWritePtr( outData, outDataMaxLength ) );
assert( outDataMaxLength > 16 );
assert( isWritePtr( outDataLength, sizeof( int ) ) );
assert( contentType >= CRYPT_CONTENT_NONE && \
contentType < CRYPT_CONTENT_LAST );
assert( isHandleRangeValid( iSigKey ) );
assert( iCmsAttributes == CRYPT_UNUSED || \
isHandleRangeValid( iCmsAttributes ) );
*outDataLength = 0;
/* Create an envelope to sign the data, add the signature key and
optional signing attributes, and pop the signed result */
setMessageCreateObjectInfo( &createInfo, CRYPT_FORMAT_CMS );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_ENVELOPE );
if( cryptStatusError( status ) )
return( status );
iCryptEnvelope = createInfo.cryptHandle;
krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
( void * ) &minBufferSize, CRYPT_ATTRIBUTE_BUFFERSIZE );
status = krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
( void * ) &inDataLength,
CRYPT_ENVINFO_DATASIZE );
if( cryptStatusOK( status ) && contentType != CRYPT_CONTENT_NONE )
status = krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
( void * ) &contentType,
CRYPT_ENVINFO_CONTENTTYPE );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
( void * ) &iSigKey,
CRYPT_ENVINFO_SIGNATURE );
if( cryptStatusOK( status ) && iCmsAttributes != CRYPT_UNUSED )
status = krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
( void * ) &iCmsAttributes,
CRYPT_ENVINFO_SIGNATURE_EXTRADATA );
if( cryptStatusOK( status ) )
{
/* If there's no data supplied, it's an attributes-only message
containing only authenticated attributes */
if( inDataLength <= 0 )
status = krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_TRUE,
CRYPT_IATTRIBUTE_ATTRONLY );
else
{
setMessageData( &msgData, ( void * ) inData, inDataLength );
status = krnlSendMessage( iCryptEnvelope, IMESSAGE_ENV_PUSHDATA,
&msgData, 0 );
}
}
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( iCryptEnvelope, IMESSAGE_ENV_PUSHDATA,
&msgData, 0 );
}
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, outData, outDataMaxLength );
status = krnlSendMessage( iCryptEnvelope, IMESSAGE_ENV_POPDATA,
&msgData, 0 );
}
krnlSendNotifier( iCryptEnvelope, IMESSAGE_DECREFCOUNT );
if( cryptStatusOK( status ) )
*outDataLength = msgData.length;
return( status );
}
int envelopeSigCheck( const void *inData, const int inDataLength,
void *outData, int *outDataLength,
const int outDataMaxLength,
const CRYPT_CONTEXT iSigCheckKey,
int *sigResult, CRYPT_CERTIFICATE *iSigningCert,
CRYPT_CERTIFICATE *iCmsAttributes )
{
CRYPT_ENVELOPE iCryptEnvelope;
MESSAGE_CREATEOBJECT_INFO createInfo;
RESOURCE_DATA msgData;
const int minBufferSize = max( MIN_BUFFER_SIZE, inDataLength );
int status;
assert( isReadPtr( inData, inDataLength ) );
assert( inDataLength > 16 );
assert( isWritePtr( outData, outDataMaxLength ) );
assert( outDataMaxLength > 16 );
assert( isWritePtr( outDataLength, sizeof( int ) ) );
assert( iSigCheckKey == CRYPT_UNUSED || \
isHandleRangeValid( iSigCheckKey ) );
assert( isWritePtr( sigResult, sizeof( int ) ) );
/* Clear return values */
*outDataLength = 0;
*sigResult = CRYPT_ERROR;
if( iSigningCert != NULL )
*iSigningCert = CRYPT_ERROR;
if( iCmsAttributes != NULL )
*iCmsAttributes = CRYPT_ERROR;
/* Create an envelope to sig.check the data, push in the signed data and
sig.check key, and pop the result. We also speculatively set the
attributes-only flag to let the enveloping code know that a signed
message with no content is a zero-data-length message rather than a
detached signature, which is what this type of message would normally
be */
setMessageCreateObjectInfo( &createInfo, CRYPT_FORMAT_AUTO );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_ENVELOPE );
if( cryptStatusError( status ) )
return( status );
iCryptEnvelope = createInfo.cryptHandle;
krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
( void * ) &minBufferSize, CRYPT_ATTRIBUTE_BUFFERSIZE );
krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_TRUE, CRYPT_IATTRIBUTE_ATTRONLY );
setMessageData( &msgData, ( void * ) inData, inDataLength );
status = krnlSendMessage( iCryptEnvelope, IMESSAGE_ENV_PUSHDATA,
&msgData, 0 );
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( iCryptEnvelope, IMESSAGE_ENV_PUSHDATA,
&msgData, 0 );
}
if( cryptStatusOK( status ) && iSigCheckKey != CRYPT_UNUSED )
status = krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
( void * ) &iSigCheckKey,
CRYPT_ENVINFO_SIGNATURE );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iCryptEnvelope, IMESSAGE_GETATTRIBUTE,
sigResult, CRYPT_ENVINFO_SIGNATURE_RESULT );
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, outData, outDataMaxLength );
status = krnlSendMessage( iCryptEnvelope, IMESSAGE_ENV_POPDATA,
&msgData, 0 );
}
if( cryptStatusOK( status ) && iSigningCert != NULL )
status = krnlSendMessage( iCryptEnvelope, IMESSAGE_GETATTRIBUTE,
iSigningCert,
CRYPT_ENVINFO_SIGNATURE );
if( cryptStatusOK( status ) && iCmsAttributes != NULL )
{
status = krnlSendMessage( iCryptEnvelope, IMESSAGE_GETATTRIBUTE,
iCmsAttributes,
CRYPT_ENVINFO_SIGNATURE_EXTRADATA );
if( cryptStatusError( status ) && iSigningCert != NULL )
{
krnlSendNotifier( *iSigningCert, IMESSAGE_DECREFCOUNT );
*iSigningCert = CRYPT_ERROR;
}
}
krnlSendNotifier( iCryptEnvelope, IMESSAGE_DECREFCOUNT );
if( cryptStatusOK( status ) )
*outDataLength = msgData.length;
return( status );
}
/****************************************************************************
* *
* Safe Text-line Read Functions *
* *
****************************************************************************/
/* Process a MIME header line. When we read data we're mostly looking for
the EOL marker. If we find more data than will fit in the input buffer,
we discard it until we find an EOL. As a secondary concern, we want to
strip leading, trailing, and repeated whitespace. We handle the former
by setting the seen-whitespace flag to true initially, this treats any
whitespace at the start of the line as superfluous and strips it. We
also handle continued lines, denoted by a semicolon or occasionally a
backslash as the last non-whitespace character. Stripping of repeated
whitespace is also handled by the seenWhitespace flag, stripping of
trailing whitespace is handled by walking back through any final
whitespace once we see the EOL, and continued lines are handled by
setting the seenContinuation flag if we see a semicolon or backslash as
the last non-whitespace character.
Finally, we also need to handle generic DoS attacks. If we see more than
10K chars in a line, we bail out */
typedef struct {
BOOLEAN seenWhitespace, seenContinuation;
int totalChars, maxSize, bufPos;
} MIME_STATE_INFO;
/* Initialise the MIME line buffer state. We set the seen-whitespace flag
initially to strip leading whitespace */
void initMIMEstate( MIME_STATE *mimeState, const int maxSize )
{
MIME_STATE_INFO *state = ( MIME_STATE_INFO * ) mimeState;
assert( isWritePtr( state, sizeof( MIME_STATE_INFO ) ) );
assert( sizeof( MIME_STATE_INFO ) <= sizeof( MIME_STATE ) );
memset( state, 0, sizeof( MIME_STATE_INFO ) );
state->seenWhitespace = TRUE; /* Catch leading whitespace */
state->maxSize = maxSize;
}
/* Add a character to the line buffer with special-case MIME-specific
processing */
int addMIMEchar( MIME_STATE *mimeState, char *buffer, int ch )
{
MIME_STATE_INFO *state = ( MIME_STATE_INFO * ) mimeState;
assert( isWritePtr( state, sizeof( MIME_STATE_INFO ) ) );
assert( buffer != NULL );
/* Don't try and process excessively long inputs, which are probably
DoSes */
if( state->totalChars++ > 10000 )
return( CRYPT_ERROR_OVERFLOW );
/* If we're over the maximum buffer size, the only character we recognise
is EOL */
if( ( state->bufPos > state->maxSize - 8 ) && ( ch != '\n' ) )
return( CRYPT_OK );
/* Process EOL */
if( ch == '\n' )
{
/* Strip trailing whitespace. At this point it's all been
canonicalised so we don't need to check for anything other than
spaces */
while( state->bufPos > 0 && buffer[ state->bufPos - 1 ] == ' ' )
state->bufPos--;
/* If we've seen a continuation market as the last non-whitespace
char, the line continues on the next one */
if( state->seenContinuation )
{
state->seenContinuation = FALSE;
return( CRYPT_OK );
}
/* We're done */
buffer[ state->bufPos ] = '\0';
return( OK_SPECIAL );
}
/* Process whitespace. We can't use isspace() for this because it
includes all sorts of extra control characters */
if( ch == ' ' || ch == '\t' )
{
if( state->seenWhitespace )
/* Ignore leading and repeated whitespace */
return( CRYPT_OK );
ch = ' '; /* Canonicalise whitespace */
}
/* Process any remaining chars */
if( ch != '\r' )
{
if( !( isPrint( ch ) ) )
return( CRYPT_ERROR_BADDATA );
buffer[ state->bufPos++ ] = ch;
state->seenWhitespace = ( ch == ' ' ) ? TRUE : FALSE;
state->seenContinuation = ( ch == ';' || ch == '\\' || \
( state->seenContinuation && \
state->seenWhitespace ) ) ? \
TRUE : FALSE;
}
return( CRYPT_OK );
}
/* Wrap up the MIME line processing */
int endMIMEstate( MIME_STATE *mimeState )
{
MIME_STATE_INFO *state = ( MIME_STATE_INFO * ) mimeState;
assert( isWritePtr( state, sizeof( MIME_STATE_INFO ) ) );
return( state->bufPos );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -