⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cmp_rd.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 4 页
字号:
		"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 + -