📄 cmp.c
字号:
"The messageTime was not sufficiently close to the system time as "
"defined by local policy",
"No certificate could be found matching the provided criteria",
"The data submitted has the wrong format",
"The authority indicated in the request is different from the one "
"creating the response token",
"The requester's data is incorrect (used for notary services)",
"Timestamp is missing but should be there (by policy)",
"The proof-of-possession failed",
"The certificate has already been revoked",
"The certificate has already been confirmed",
"Invalid integrity, password based instead of signature or vice "
"versa",
"Invalid recipient nonce, either missing or wrong value",
"The TSA's time source is not available",
"The requested TSA policy is not supported by the TSA",
"The requested extension is not supported by the TSA",
"The additional information requested could not be understood or is "
"not available",
"Invalid sender nonce, either missing or wrong size",
"Invalid certificate template or missing mandatory information",
"Signer of the message unknown or not trusted",
"The transaction identifier is already in use",
"The version of the message is not supported",
"The sender was not authorized to make the preceding request or "
"perform the preceding action",
"The request cannot be handled due to system unavailability",
"The request cannot be handled due to system failure",
"Certificate cannot be issued because a duplicate certificate "
"already exists",
NULL
};
int bitIndex = 0, bitFlags = value;
/* Find the first failure string corresponding to a bit set in the
failure info */
if( !bitFlags )
return( "Missing PKI failure code" );
while( !( bitFlags & 1 ) )
{
bitIndex++;
bitFlags >>= 1;
}
if( bitIndex >= sizeof( failureStrings ) / sizeof( char * ) )
return( "Unknown PKI failure code" );
return( ( char * ) failureStrings[ bitIndex ] );
}
/* Read/write PKIStatus information:
PKIStatusInfo ::= SEQUENCE {
status INTEGER,
statusString SEQUENCE OF UTF8String OPTIONAL,
failInfo BIT STRING OPTIONAL
} */
static int readFreeText( STREAM *stream, char *string, const int maxLength )
{
int endPos, stringLength, status;
/* Read the status string(s). There can be more than one of these,
there's no indication of what the subsequent ones are used for (and
not much we can do with them in any case) so we skip them */
readSequence( stream, &endPos );
endPos += ( int ) stell( stream );
status = readOctetStringTag( stream, string, &stringLength, maxLength,
BER_STRING_UTF8 );
if( cryptStatusError( status ) )
{
*string = '\0';
return( status );
}
string[ stringLength ] = '\0';
return( ( stell( stream ) < endPos ) ? \
sSkip( stream, endPos - stell( stream ) ) : CRYPT_OK );
}
static int readPkiStatusInfo( STREAM *stream, int *errorCode,
char *errorMessage )
{
long value, endPos;
int length, status;
/* Clear the return values */
*errorCode = 0;
*errorMessage = '\0';
/* Read the outer wrapper and status value */
readSequence( stream, &length );
endPos = stell( stream ) + length;
status = readShortInteger( stream, &value );
if( cryptStatusError( status ) )
return( status );
*errorCode = ( int ) value;
if( stell( stream ) < endPos && peekTag( stream ) == BER_SEQUENCE )
{
status = readFreeText( stream, errorMessage, MAX_ERRMSG_SIZE - 1 );
if( cryptStatusError( status ) )
return( status );
}
if( stell( stream ) < endPos )
{
char textBitString[ 64 ];
int value, textBitStringLen, errorMsgLen;
int i, noBits, bitMask, bitNo = -1;
/* Read the failure info and slot it into the error string */
status = readBitString( stream, &value );
if( cryptStatusError( status ) )
return( status );
i = value;
for( noBits = 0; i && noBits < 32; noBits++ )
i >>= 1;
bitMask = 1 << ( noBits - 1 );
for( i = 0; i < noBits; i++ )
{
if( value & bitMask )
{
bitNo = ( bitNo == -1 ) ? ( noBits - 1 ) - i : -2;
textBitString[ i ] = '1';
}
else
textBitString[ i ] = '0';
bitMask >>= 1;
}
if( bitNo >= 0 )
sprintf( textBitString + i, "'B (bit %d): ", bitNo );
else
strcpy( textBitString + i, "'B: " );
textBitStringLen = strlen( textBitString );
if( ( errorMsgLen = strlen( errorMessage ) ) != 0 )
{
memmove( errorMessage + textBitStringLen, errorMessage,
min( errorMsgLen + 1, MAX_ERRMSG_SIZE - textBitStringLen ) );
errorMessage[ MAX_ERRMSG_SIZE - 1 ] = '\0';
memcpy( errorMessage, textBitString, textBitStringLen );
}
else
/* If there's a failure code present, turn it into an error
string */
if( value )
{
memcpy( errorMessage, textBitString, textBitStringLen + 1 );
strncat( errorMessage, getFailureString( value ),
MAX_ERRMSG_SIZE - textBitStringLen );
}
/* If we can return something more useful than the generic "failed"
error code, try and do so */
if( value & CMPFAILINFO_BADALG )
return( CRYPT_ERROR_NOTAVAIL );
if( ( value & CMPFAILINFO_BADMESSAGECHECK ) || \
( value & CMPFAILINFO_BADPOP ) || \
( value & CMPFAILINFO_WRONGINTEGRITY ) )
return( CRYPT_ERROR_WRONGKEY );
if( ( value & CMPFAILINFO_BADREQUEST ) || \
( value & CMPFAILINFO_NOTAUTHORIZED ) )
return( CRYPT_ERROR_PERMISSION );
if( value & CMPFAILINFO_BADDATAFORMAT )
return( CRYPT_ERROR_BADDATA );
if( ( value & CMPFAILINFO_UNACCEPTEDPOLICY ) || \
( value & CMPFAILINFO_UNACCEPTEDEXTENSION ) || \
( value & CMPFAILINFO_BADCERTTEMPLATE ) )
return( CRYPT_ERROR_INVALID );
if( ( value & CMPFAILINFO_TRANSACTIONIDINUSE ) || \
( value & CMPFAILINFO_DUPLICATECERTREQ ) )
return( CRYPT_ERROR_DUPLICATE );
}
/* A PKI status code is a bit difficult to turn into anything useful,
the best we can do is to report that that operation failed and let
the user get the exact details from the PKI status info */
return( ( *errorCode == PKISTATUS_OK || \
*errorCode == PKISTATUS_OK_WITHINFO ) ? \
CRYPT_OK : CRYPT_ERROR_FAILED );
}
static int writePkiStatusInfo( STREAM *stream, const int status,
const long pkiFailureInfo )
{
const long localPKIFailureInfo = \
( pkiFailureInfo != CMPFAILINFO_OK ) ? pkiFailureInfo : \
( status == CRYPT_ERROR_NOTAVAIL ) ? CMPFAILINFO_BADALG : \
( status == CRYPT_ERROR_SIGNATURE ) ? CMPFAILINFO_BADMESSAGECHECK : \
( status == CRYPT_ERROR_PERMISSION ) ? CMPFAILINFO_BADREQUEST : \
( status == CRYPT_ERROR_BADDATA ) ? CMPFAILINFO_BADDATAFORMAT : \
( status == CRYPT_ERROR_INVALID ) ? CMPFAILINFO_BADCERTTEMPLATE : \
( status == CRYPT_ERROR_DUPLICATE ) ? CMPFAILINFO_DUPLICATECERTREQ : \
0;
const int length = \
sizeofShortInteger( PKISTATUS_REJECTED ) + \
( localPKIFailureInfo ? sizeofBitString( localPKIFailureInfo ) : 0 );
/* If we've been passed a null stream, it's a size request only */
if( stream == NULL )
return( objSize( sizeofObject( length ) ) );
/* Write the error status info. If there's a specific failure info code
set by the caller we use that, otherwise we try and convert the
cryptlib status into an appropriate failure info value */
writeSequence( stream, objSize( length ) );
writeSequence( stream, length );
writeShortInteger( stream, PKISTATUS_REJECTED, DEFAULT_TAG );
if( localPKIFailureInfo )
writeBitString( stream, localPKIFailureInfo, DEFAULT_TAG );
return( CRYPT_OK );
}
/* Write full cert ID info. This is written as an attribute in the
generalInfo field of the message header to allow unambiguous
identification of the signing cert, which the standard CMP format can't
do. Although CMP uses a gratuitously incompatible definition of the
standard attribute type (calling it InfoTypeAndValue), it's possible to
shoehorn a standard attribute type in by taking the "ANY" in "ANY DEFINED
BY x" to mean "SET OF AttributeValue" (for once the use of archaic ASN.1
is a help, since it's so imprecise that we can shovel in anything and it's
still valid):
SigningCertificate ::= SEQUENCE {
certs SEQUENCE OF ESSCertID -- Size (1)
} */
static int writeCertID( STREAM *stream, const CRYPT_CONTEXT iCryptCert )
{
RESOURCE_DATA msgData;
int payloadSize, status;
/* Find out how big the payload will be */
setResourceData( &msgData, NULL, 0 );
status = krnlSendMessage( iCryptCert, RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_ESSCERTID );
if( cryptStatusError( status ) )
return( status );
payloadSize = ( int ) \
sizeofObject( sizeofObject( msgData.length ) );
/* If we've been passed a null stream, it's a size request only */
if( stream == NULL )
return( ( int ) sizeofObject( sizeofOID( OID_ESS_CERTID ) + \
sizeofObject( payloadSize ) ) );
/* Write the signing cert ID info */
writeSequence( stream, sizeofOID( OID_ESS_CERTID ) + \
( int ) sizeofObject( payloadSize ) );
writeOID( stream, OID_ESS_CERTID );
writeSet( stream, payloadSize );
writeSequence( stream,
sizeofObject( msgData.length ) );
writeSequence( stream, msgData.length );
setResourceData( &msgData, sMemBufPtr( stream ),
sMemDataLeft( stream ) );
status = krnlSendMessage( iCryptCert, RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_ESSCERTID );
if( cryptStatusOK( status ) )
sSkip( stream, msgData.length );
return( status );
}
/* Read and process a cert encrypted with CMP's garbled reinvention of CMS
content:
EncryptedCert ::= SEQUENCE {
dummy [0] ... OPTIONAL, -- Ignored
cekAlg [1] AlgorithmIdentifier,-- CEK algorithm
encCEK [2] BIT STRING, -- Encrypted CEK
dummy [3] ... OPTIONAL, -- Ignored
dummy [4] ... OPTIONAL, -- Ignored
encData BIT STRING -- Encrypted cert
} */
static int processEncryptedCert( STREAM *stream,
const CRYPT_CONTEXT iImportContext )
{
CRYPT_CONTEXT iSessionKey;
MECHANISM_WRAP_INFO mechanismInfo;
QUERY_INFO queryInfo;
BYTE *encKeyPtr;
int encKeyLength, encCertLength, status;
/* Read the CEK algorithm identifier and encrypted CEK. All of the
values are optional although there's no indication of why or what
you're supposed to do if they're not present (OTOH for others there's
no indication of what you're supposed to do when they're present
either) so we treat an absent required value as an error and ignore
the others */
readSequence( stream, NULL );
if( peekTag( stream ) == MAKE_CTAG( CTAG_EV_DUMMY1 ) )
readUniversal( stream ); /* Junk */
status = readContextAlgoID( stream, &iSessionKey, &queryInfo,
CTAG_EV_CEKALGO );
if( cryptStatusError( status ) ) /* CEK algo */
return( status );
status = readBitStringHole( stream, &encKeyLength, CTAG_EV_ENCCEK );
if( cryptStatusOK( status ) && /* Encrypted CEK */
( encKeyLength < 56 || encKeyLength > CRYPT_MAX_PKCSIZE ) )
status = CRYPT_ERROR_OVERFLOW;
if( cryptStatusOK( status ) )
{
encKeyPtr = sMemBufPtr( stream );
sSkip( stream, encKeyLength );
if( peekTag( stream ) == MAKE_CTAG( CTAG_EV_DUMMY2 ) )
readUniversal( stream ); /* Junk */
if( peekTag( stream ) == MAKE_CTAG( CTAG_EV_DUMMY3 ) )
readUniversal( stream ); /* Junk */
status = readBitStringHole( stream, &encCertLength, DEFAULT_TAG );
}
if( cryptStatusOK( status ) && /* Encrypted cert */
( encCertLength < 128 || encCertLength > 8192 ) )
status = CRYPT_ERROR_BADDATA;
if( cryptStatusOK( status ) && \
( queryInfo.cryptMode == CRYPT_MODE_ECB || \
queryInfo.cryptMode == CRYPT_MODE_CBC ) )
{
int blockSize;
/* Make sure the data length is valid, checking at this point saves
a lot of unnecessary processing and allows us to return a more
meaningful error code */
krnlSendMessage( iSessionKey, RESOURCE_IMESSAGE_GETATTRIBUTE,
&blockSize, CRYPT_CTXINFO_BLOCKSIZE );
if( queryInfo.size % blockSize )
status = CRYPT_ERROR_BADDATA;
}
if( cryptStatusError( status ) )
{
krnlSendNotifier( iSessionKey, RESOURCE_IMESSAGE_DECREFCOUNT );
return( status );
}
/* Copy the encrypted key to the buffer and import it into the session
key context */
setMechanismWrapInfo( &mechanismInfo, encKeyPtr, encKeyLength,
NULL, 0, iSessionKey, iImportContext,
CRYPT_UNUSED );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_DEV_IMPORT, &mechanismInfo,
MECHANISM_PKCS1 );
clearMechanismInfo( &mechanismInfo );
if( cryptStatusError( status ) )
{
krnlSendNotifier( iSessionKey,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -