📄 cmp_rd.c
字号:
"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 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 += stell( stream );
status = readCharacterString( stream, string, &stringLength, maxLength,
BER_STRING_UTF8 );
if( cryptStatusError( status ) )
{
strcpy( string, "Invalid PKI free text" );
return( status );
}
string[ stringLength ] = '\0';
return( ( stell( stream ) < endPos ) ? \
sSkip( stream, endPos - stell( stream ) ) : CRYPT_OK );
}
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 ) )
{
strcpy( errorMessage, "Invalid PKI status value" );
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 bitString, textBitStringLen, errorMsgLen;
int i, noBits, bitMask, bitNo = -1;
/* Read the failure info and slot it into the error string */
status = readBitString( stream, &bitString );
if( cryptStatusError( status ) )
{
strcpy( errorMessage, "Invalid PKI failure info" );
return( status );
}
i = bitString;
for( noBits = 0; i > 0 && noBits < 32; noBits++ )
i >>= 1;
bitMask = 1 << ( noBits - 1 );
for( i = 0; i < noBits; i++ )
{
if( bitString & 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( bitString )
{
memcpy( errorMessage, textBitString, textBitStringLen + 1 );
strncat( errorMessage, getFailureString( bitString ),
MAX_ERRMSG_SIZE - textBitStringLen );
}
/* If we can return something more useful than the generic "failed"
error code, try and do so */
if( bitString & CMPFAILINFO_BADALG )
return( CRYPT_ERROR_NOTAVAIL );
if( ( bitString & CMPFAILINFO_BADMESSAGECHECK ) || \
( bitString & CMPFAILINFO_BADPOP ) || \
( bitString & CMPFAILINFO_WRONGINTEGRITY ) )
return( CRYPT_ERROR_WRONGKEY );
if( ( bitString & CMPFAILINFO_BADREQUEST ) || \
( bitString & CMPFAILINFO_SIGNERNOTTRUSTED ) || \
( bitString & CMPFAILINFO_NOTAUTHORIZED ) )
return( CRYPT_ERROR_PERMISSION );
if( bitString & CMPFAILINFO_BADDATAFORMAT )
return( CRYPT_ERROR_BADDATA );
if( ( bitString & CMPFAILINFO_UNACCEPTEDPOLICY ) || \
( bitString & CMPFAILINFO_UNACCEPTEDEXTENSION ) || \
( bitString & CMPFAILINFO_BADCERTTEMPLATE ) )
return( CRYPT_ERROR_INVALID );
if( ( bitString & CMPFAILINFO_TRANSACTIONIDINUSE ) || \
( bitString & 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 the 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 );
}
#endif /* USE_CMP || USE_TSP */
#ifdef USE_CMP
/****************************************************************************
* *
* PKI Body Functions *
* *
****************************************************************************/
/* Read request body */
static int readRequestBody( STREAM *stream, SESSION_INFO *sessionInfoPtr,
CMP_PROTOCOL_INFO *protocolInfo,
const int messageType )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
RESOURCE_DATA msgData;
BYTE authCertID[ CRYPT_MAX_HASHSIZE ];
int value, length, status;
/* Import the CRMF request */
status = readSequence( stream, &length );
if( cryptStatusOK( status ) && length > sMemDataLeft( stream ) )
status = CRYPT_ERROR_UNDERFLOW;
if( cryptStatusOK( status ) )
{
setMessageCreateObjectIndirectInfo( &createInfo,
sMemBufPtr( stream ), length,
( messageType == CTAG_PB_P10CR ) ? \
CRYPT_CERTTYPE_CERTREQUEST : \
( messageType == CTAG_PB_RR ) ? \
CRYPT_CERTTYPE_REQUEST_REVOCATION : \
CRYPT_CERTTYPE_REQUEST_CERT );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
}
if( cryptStatusError( status ) )
{
protocolInfo->pkiFailInfo = CMPFAILINFO_BADCERTTEMPLATE;
retExt( sessionInfoPtr, status, "Invalid CRMF request" );
}
sessionInfoPtr->iCertRequest = createInfo.cryptHandle;
/* If the request is from an encryption-only key, remember this so that
we can peform special-case processing later on */
status = krnlSendMessage( sessionInfoPtr->iCertRequest,
IMESSAGE_GETATTRIBUTE, &value,
CRYPT_CERTINFO_SELFSIGNED );
if( cryptStatusOK( status ) && !value )
{
/* If the request indicates that it's a signing key then it has to
be signed */
status = krnlSendMessage( sessionInfoPtr->iCertRequest,
IMESSAGE_GETATTRIBUTE, &value,
CRYPT_CERTINFO_KEYUSAGE );
if( cryptStatusOK( status ) && \
( value & ( CRYPT_KEYUSAGE_DIGITALSIGNATURE | \
CRYPT_KEYUSAGE_NONREPUDIATION ) ) )
{
protocolInfo->pkiFailInfo = CMPFAILINFO_BADCERTTEMPLATE;
retExt( sessionInfoPtr, CRYPT_ERROR_INVALID,
"CRMF request is for a signing key but the request "
"isn't signed" );
}
protocolInfo->cryptOnlyKey = TRUE;
}
/* Record the identity of the PKI user (for a MAC'd request) or cert (for
a signed request) that authorised this request */
setMessageData( &msgData, authCertID, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( protocolInfo->useMACreceive ? \
sessionInfoPtr->cmpUserInfo : \
sessionInfoPtr->iAuthInContext,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_FINGERPRINT_SHA );
if( cryptStatusOK( status ) )
status = krnlSendMessage( sessionInfoPtr->iCertRequest,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_AUTHCERTID );
if( cryptStatusError( status ) || messageType != CTAG_PB_IR )
return( status );
/* If it's an ir, the subject may not know their DN or may only know
their CN, in which case they'll send an empty/CN-only subject DN in
the hope that we can fill it in for them. In addition there may be
other constraints that the CA wants to apply, these are handled by
applying the PKI user info to the request */
status = krnlSendMessage( sessionInfoPtr->iCertRequest,
IMESSAGE_SETATTRIBUTE,
&sessionInfoPtr->cmpUserInfo,
CRYPT_IATTRIBUTE_PKIUSERINFO );
if( cryptStatusError( status ) )
{
protocolInfo->pkiFailInfo = CMPFAILINFO_BADCERTTEMPLATE;
retExt( sessionInfoPtr, CRYPT_ERROR_INVALID,
"User information in request can't be reconciled with our "
"information for the user" );
}
return( CRYPT_OK );
}
/* Read response body */
static int readResponseBody( STREAM *stream, SESSION_INFO *sessionInfoPtr,
CMP_PROTOCOL_INFO *protocolInfo )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
void *bodyInfoPtr;
int bodyStart, bodyLength, tag, status;
/* If it's a revocation response, the only returned data is the status
value */
if( protocolInfo->operation == CTAG_PB_RR )
{
readSequence( stream, NULL ); /* Outer wrapper */
readSequence( stream, NULL ); /* Inner wrapper */
return( readPkiStatusInfo( stream, &sessionInfoPtr->errorCode,
sessionInfoPtr->errorMessage ) );
}
/* It's a cert response, unwrap the body to find the certificate
payload */
readSequence( stream, NULL ); /* Outer wrapper */
if( peekTag( stream ) == MAKE_CTAG( 1 ) )
readUniversal( stream ); /* caPubs */
readSequence( stream, NULL );
readSequence( stream, NULL ); /* Inner wrapper */
readUniversal( stream ); /* certReqId */
status = readPkiStatusInfo( stream, &sessionInfoPtr->errorCode,
sessionInfoPtr->errorMessage );
if( cryptStatusOK( status ) )
{
readSequence( stream, NULL ); /* certKeyPair wrapper */
tag = EXTRACT_CTAG( peekTag( stream ) );
status = readConstructed( stream, &bodyLength, tag );
if( cryptStatusOK( status ) && bodyLength > sMemDataLeft( stream ) )
status = CRYPT_ERROR_UNDERFLOW;
}
if( cryptStatusError( status ) )
return( status );
/* Process the returned cert as required */
bodyInfoPtr = sMemBufPtr( stream );
bodyStart = stell( stream );
switch( tag )
{
case CTAG_CK_CERT:
/* Plaintext cert, we're done */
break;
case CTAG_CK_ENCRYPTEDCERT:
/* Cert encrypted with CMP's garbled attempt at doing CMS, try
and decrypt it */
status = readEncryptedCert( stream, sessionInfoPtr->privateKey,
sessionInfoPtr );
break;
case CTAG_CK_NEWENCRYPTEDCERT:
/* Cert encrypted with CMS, unwrap it */
status = envelopeUnwrap( bodyInfoPtr, bodyLength,
bodyInfoPtr, &bodyLength,
bodyLength,
sessionInfoPtr->privateKey );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr,
cryptArgError( status ) ? \
CRYPT_ERROR_FAILED : status,
"Couldn't decrypt CMS enveloped certificate" );
break;
default:
retExt( sessionInfoPtr, status,
"Unknown returned certificate encapsulation type %d",
tag );
}
if( cryptStatusError( status ) )
return( status );
/* In order to acknowledge receipt of this message we have to return at a
later point a hash of the cert carried in this message created using
the hash algorithm used in the cert signature, so we have to tunnel
into the cert to extract this information for later use. This makes
the CMP-level transport layer dependant on the certificate format
it's carrying (so the code will repeatedly break every time a new
cert format is added), but that's what the standard requires */
readSequence( stream, NULL ); /* Outer wrapper */
readSequence( stream, NULL ); /* Inner wrapper */
if( peekTag( stream ) == MAKE_CTAG( 0 ) )
readUniversal( stream ); /* Version */
readUniversal( stream ); /* Serial number */
status = readAlgoIDex( stream, NULL, &protocolInfo->confHashAlgo, NULL );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Couldn't extract confirmation hash type from certificate" );
if( protocolInfo->confHashAlgo != CRYPT_ALGO_MD5 && \
protocolInfo->confHashAlgo != CRYPT_ALGO_SHA )
/* Certs can only provide MD5 and SHA-1 fingerprints */
retExt( sessionInfoPtr, CRYPT_ERROR_NOTAVAIL,
"Can't confirm certificate issue using algorithm %d",
protocolInfo->confHashAlgo );
/* Import the cert as a cryptlib object */
setMessageCreateObjectIndirectInfo( &createInfo, bodyInfoPtr, bodyLength,
CRYPT_CERTTYPE_CERTIFICATE );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT_INDIRECT, &createInfo,
OBJECT_TYPE_CERTIFICATE );
if( cryptStatusOK( status ) )
sessionInfoPtr->iCertResponse = createInfo.cryptHandle;
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Invalid returned certificate" );
return( CRYPT_OK );
}
/* Read conf body */
static int readConfBody( STREAM *stream, SESSION_INFO *sessionInfoPtr,
CMP_PROTOCOL_INFO *protocolInfo )
{
RESOURCE_DATA msgData;
BYTE certHash[ CRYPT_MAX_HASHSIZE ];
int length, status;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -