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

📄 cmp_rd.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 5 页
字号:
			( value & ( CRYPT_KEYUSAGE_DIGITALSIGNATURE | \
						CRYPT_KEYUSAGE_NONREPUDIATION ) ) )
			{
			protocolInfo->pkiFailInfo = CMPFAILINFO_BADCERTTEMPLATE;
			retExt( CRYPT_ERROR_INVALID,
					( CRYPT_ERROR_INVALID, SESSION_ERRINFO, 
					  "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 ? \
								cmpInfo->userInfo : \
								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, &cmpInfo->userInfo,
							  CRYPT_IATTRIBUTE_PKIUSERINFO );
	if( cryptStatusError( status ) )
		{
		protocolInfo->pkiFailInfo = CMPFAILINFO_BADCERTTEMPLATE;
		retExt( CRYPT_ERROR_INVALID,
				( CRYPT_ERROR_INVALID, SESSION_ERRINFO, 
				  "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 = DUMMY_INIT_PTR;
	int 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->errorInfo ) );
		}

	/* 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->errorInfo );
	if( cryptStatusError( status ) )
		return( status );
	readSequence( stream, NULL );			/* certKeyPair wrapper */
	tag = peekTag( stream );
	if( cryptStatusError( tag ) )
		return( tag );
	tag = EXTRACT_CTAG( tag );
	status = readConstructed( stream, &bodyLength, tag );
	if( cryptStatusOK( status ) )
		status = sMemGetDataBlock( stream, &bodyInfoPtr, bodyLength );
	if( cryptStatusError( status ) )
		return( status );

	/* Process the returned cert as required */
	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,
										SESSION_ERRINFO );
			break;

		case CTAG_CK_NEWENCRYPTEDCERT:
			/* Cert encrypted with CMS, unwrap it */
			status = envelopeUnwrap( bodyInfoPtr, bodyLength,
									 bodyInfoPtr, bodyLength, &bodyLength,
									 sessionInfoPtr->privateKey );
			if( cryptStatusError( status ) )
				{
				retExt( cryptArgError( status ) ? \
						CRYPT_ERROR_FAILED : status,
						( cryptArgError( status ) ? \
						  CRYPT_ERROR_FAILED : status, SESSION_ERRINFO,
						  "Couldn't decrypt CMS enveloped certificate" ) );
				}
			break;

		default:
			retExt( status,
					( status, SESSION_ERRINFO, 
					  "Unknown returned certificate encapsulation type %d",
					  tag ) );
		}
	if( cryptStatusError( status ) )
		return( status );

	/* 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( cryptStatusError( status ) )
		{
		retExt( status,
				( status, SESSION_ERRINFO, 
				  "Invalid returned certificate" ) );
		}
	sessionInfoPtr->iCertResponse = createInfo.cryptHandle;

	/* 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.  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 */
	status = krnlSendMessage( sessionInfoPtr->iCertResponse,
							  IMESSAGE_GETATTRIBUTE,
							  &protocolInfo->confHashAlgo,
							  CRYPT_IATTRIBUTE_CERTHASHALGO );
	if( cryptStatusError( status ) )
		{
		retExt( status,
				( status, SESSION_ERRINFO, 
				  "Couldn't extract confirmation hash type from "
				  "certificate" ) );
		}
	if( protocolInfo->confHashAlgo != CRYPT_ALGO_MD5 && \
		protocolInfo->confHashAlgo != CRYPT_ALGO_SHA1 )
		{
		/* Certs can only provide MD5 and SHA-1 fingerprints */
		retExt( CRYPT_ERROR_NOTAVAIL,
				( CRYPT_ERROR_NOTAVAIL, SESSION_ERRINFO, 
				  "Can't confirm certificate issue using algorithm %d",
				  protocolInfo->confHashAlgo ) );
		}

	return( CRYPT_OK );
	}

/* Read conf body */

static int readConfBody( STREAM *stream, SESSION_INFO *sessionInfoPtr,
						 CMP_PROTOCOL_INFO *protocolInfo )
	{
	MESSAGE_DATA msgData;
	BYTE certHash[ CRYPT_MAX_HASHSIZE + 8 ];
	int length, status;

	/* Read the client's returned confirmation information */
	status = readSequence( stream, &length );
	if( cryptStatusOK( status ) && length <= 0 )
		{
		/* Missing certStatus, the client has rejected the cert.  This isn't
		   an explicit error since it's a valid protocol outcome, so we
		   return an OK status but set the overall protocol status to a
		   generic error value to indicate that we don't want to continue
		   normally */
		protocolInfo->status = CRYPT_ERROR;
		return( CRYPT_OK );
		}
	readSequence( stream, NULL );
	status = readOctetString( stream, certHash, &length,
							  8, CRYPT_MAX_HASHSIZE );
	if( cryptStatusError( status ) )
		retExt( status, 
				( status, SESSION_ERRINFO, "Invalid cert confirmation" ) );

	/* Get the local cert hash and compare it to the client's one.  Since
	   we're the server, this is a cryptlib-issued cert so we know that
	   it'll always use SHA-1 */
	setMessageData( &msgData, certHash, length );
	status = krnlSendMessage( sessionInfoPtr->iCertResponse,
							  IMESSAGE_COMPARE, &msgData,
							  MESSAGE_COMPARE_FINGERPRINT );
	if( cryptStatusError( status ) )
		{
		/* The user is confirming an unknown cert, the best that we can do
		   is return a generic cert-mismatch error */
		protocolInfo->pkiFailInfo = CMPFAILINFO_BADCERTID;
		retExt( CRYPT_ERROR_NOTFOUND,
				( CRYPT_ERROR_NOTFOUND, SESSION_ERRINFO, 
				  "Returned cert hash doesn't match issued certificate" ) );
		}
	return( CRYPT_OK );
	}

/* Read genMsg body */

static int readGenMsgBody( STREAM *stream, SESSION_INFO *sessionInfoPtr,
						   const BOOLEAN isRequest )
	{
	int bodyLength, status;

	status = readSequence( stream, &bodyLength );
	if( cryptStatusError( status ) )
		retExt( CRYPT_ERROR_BADDATA,
				( CRYPT_ERROR_BADDATA, SESSION_ERRINFO, 
				  "Invalid genMsg header" ) );
	if( isRequest )
		{
		/* It's a request GenMsg, check for a PKIBoot request */
		if( bodyLength < sizeofObject( sizeofOID( OID_PKIBOOT ) ) || \
			bodyLength > sMemDataLeft( stream ) )
			{
			retExt( CRYPT_ERROR_BADDATA,
					( CRYPT_ERROR_BADDATA, SESSION_ERRINFO, 
					  "Invalid genMsg length %d", bodyLength ) );
			}
		readSequence( stream, NULL );
		status = readFixedOID( stream, OID_PKIBOOT, 
							   sizeofOID( OID_PKIBOOT ) );
		if( cryptStatusError( status ) )
			{
			retExt( CRYPT_ERROR_NOTAVAIL,
					( CRYPT_ERROR_NOTAVAIL, SESSION_ERRINFO, 
					  "Invalid genMsg type, expected PKIBoot request" ) );
			}
		return( CRYPT_OK );
		}

	/* It's a PKIBoot response with the InfoTypeAndValue handled as CMS
	   content (see the comment for writeGenMsgBody()), import the cert
	   trust list.  Since this isn't a true cert chain and isn't used as
	   such, we use data-only certs (specified using the special-case
	   CRYPT_ICERTTYPE_CTL type specifier) */
	status = importCertFromStream( stream, &sessionInfoPtr->iCertResponse,
								   CRYPT_ICERTTYPE_CTL, bodyLength );
	if( cryptStatusError( status ) )
		retExt( status, 
				( status, SESSION_ERRINFO, "Invalid PKIBoot response" ) );
	return( CRYPT_OK );
	}

/* Read error body */

static int readErrorBody( STREAM *stream, SESSION_INFO *sessionInfoPtr )
	{
	ERROR_INFO *errorInfo = &sessionInfoPtr->errorInfo;
	int endPos, length, status;

	/* Read the outer wrapper and PKI status info.  An error return status
	   is valid when we read the status info since we're reading an error
	   status and converting it into a cryptlib status, so we don't exit
	   unless it's a problem with the status info itself */
	readConstructed( stream, NULL, CTAG_PB_ERROR );
	readSequence( stream, &length );	/* Outer wrapper */
	endPos = stell( stream ) + length;
	status = readPkiStatusInfo( stream, &sessionInfoPtr->errorInfo );
	if( status == CRYPT_ERROR_BADDATA || status == CRYPT_ERROR_UNDERFLOW )
		return( status );

	/* In addition to the PKI status info there can be another layer of
	   error information wrapped around it which is exactly the same only
	   different, so if we haven't got anything from the status info we
	   check to see whether this layer can give us anything */
	if( stell( stream ) < endPos && peekTag( stream ) == BER_INTEGER )
		{
		/* If there's an error code present and we haven't already set the
		   error code from the pkiStatusInfo, set it now */
		if( !errorInfo->errorCode )
			{
			long value;

			status = readShortInteger( stream, &value );
			if( cryptStatusOK( status ) )
				errorInfo->errorCode = ( int ) value;
			}
		else
			readUniversal( stream );
		}
	if( stell( stream ) < endPos && peekTag( stream ) == BER_SEQUENCE && \
		errorInfo->errorStringLength <= 0 )
		{
		char errorMessage[ MAX_ERRMSG_SIZE + 8 ];
		int errorMessageLength;

		/* Read the error text, ignoring any possible error status since the
		   overall error code from the status info is more meaningful than
		   a data format problem in trying to read the error text */
		status = readFreeText( stream, errorMessage, MAX_ERRMSG_SIZE, 
							   &errorMessageLength );
		if( cryptStatusOK( status ) )
			setErrorString( errorInfo, errorMessage, errorMessageLength );
		}

	return( status );
	}

/****************************************************************************
*																			*
*								Read a PKI Header							*
*																			*
****************************************************************************/

/* Read a PKI header and make sure that it matches the header that we sent
   (for EE or non-initial CA/RA messages) or set up the EE information in
   response to an initial message (for an initial CA/RA message).  We ignore
   all the redundant fields in the header that don't directly affect the
   protocol, based on the results of CMP interop testing this appears to be
   standard practice among implementors.  This also helps get around problems
   with implementations that get the fields wrong, since most of the fields
   aren't generally useful it doesn't affect the processing while making the
   code more tolerant of implementation errors:

	header				SEQUENCE {
		version			INTEGER (2),
		dummy		[4]	EXPLICIT DirectoryName,		-- Ignored
		senderDN	[4]	EXPLICIT DirectoryName,		-- Copied if non-clib
		protAlgo	[1]	EXPLICIT AlgorithmIdentifier,
		protKeyID	[2] EXPLICIT OCTET STRING,		-- Copied if changed
		dummy		[3] EXPLICIT OCTET STRING,		-- Ignored
		transID		[4] EXPLICIT OCTET STRING,
		nonce		[5] EXPLICIT OCTET STRING,		-- Copied if non-clib
		dummy		[6] EXPLICIT OCTET STRING,		-- Ignored
		dummy		[7] SEQUENCE OF UTF8String,		-- Ignored
		generalInfo	[8] EXPLICIT SEQUENCE OF Info OPT	-- cryptlib-specific info
		} */

static int readPkiHeader( STREAM *stream, CMP_PROTOCOL_INFO *protocolInfo,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -