static int serverTransact( INOUT SESSION_INFO *sessionInfoPtr )
	{
	SCEP_PROTOCOL_INFO protocolInfo;
	HTTP_DATA_INFO httpDataInfo;
	HTTP_URI_INFO httpReqInfo;
	BOOLEAN requestDataOK;
	int requestCount, length = DUMMY_INIT, status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );

	/* SCEP is a weird protocol that started out as a basic IPsec 
	   certificate-provisioning mechanism for routers but then had a pile of 
	   additional functionality bolted onto it via HTTP mechanisms rather 
	   than having the protocol itself handle the extra functionality.  
	   Because of this we have to handle not only the standard HTTP-as-a-
	   substrate mechanism used by the other protocols but also HTTP GET 
	   requests for additional information that the original protocol didn't 
	   accomodate */
	sessionInfoPtr->receiveBufEnd = 0;
	sioctlSet( &sessionInfoPtr->stream, STREAM_IOCTL_HTTPREQTYPES, 
			   STREAM_HTTPREQTYPE_ANY );
	for( requestCount = 0; requestCount < 5; requestCount++ )
		{
		initHttpDataInfoEx( &httpDataInfo, sessionInfoPtr->receiveBuffer,
							sessionInfoPtr->receiveBufSize, &httpReqInfo );
		status = sread( &sessionInfoPtr->stream, &httpDataInfo,
						sizeof( HTTP_DATA_INFO ) );
		if( cryptStatusError( status ) )
			{
			sNetGetErrorInfo( &sessionInfoPtr->stream, 
							  &sessionInfoPtr->errorInfo );
			return( status );
			}

		/* If it's a proper SCEP protocol message, switch back to handling 
		   the main protocol */
		if( httpDataInfo.reqType != STREAM_HTTPREQTYPE_GET )
			{
			sioctlSet( &sessionInfoPtr->stream, STREAM_IOCTL_HTTPREQTYPES, 
					   STREAM_HTTPREQTYPE_POST );
			length = httpDataInfo.bytesAvail;
			break;
			}

		/* It's one of the bolted-on additions to the basic SCEP protocol,
		   handle it specially */
		status = processAdditionalScepRequest( sessionInfoPtr, 
											   &httpReqInfo );
		if( cryptStatusError( status ) )
			return( status );
		}
	if( requestCount >= 5 )
		{
		/* The exact type of error response to send at this point is a bit
		   tricky, the least inappropriate one is probably 
		   CRYPT_ERROR_DUPLICATE to indicate that too many duplicate 
		   requests were sent, since to get here the client would have had 
		   to send repeated identical bolt-on requests */
		sendCertErrorResponse( sessionInfoPtr, CRYPT_ERROR_DUPLICATE );
		return( CRYPT_ERROR_OVERFLOW );
		}

	/* Unfortunately we can't use readPkiDatagram() because of the weird 
	   dual-purpose HTTP transport used in SCEP so we have to duplicate 
	   portions of readPkiDatagram() here.  See the readPkiDatagram() 
	   function for code comments explaining the following operations */
	if( length < 4 || length >= MAX_INTLENGTH )
		{
		sendCertErrorResponse( sessionInfoPtr, CRYPT_ERROR_BADDATA );
		retExt( CRYPT_ERROR_UNDERFLOW,
				( CRYPT_ERROR_UNDERFLOW, SESSION_ERRINFO, 
				  "Invalid PKI message length %d", length ) );
		}
	status = length = \
				checkObjectEncoding( sessionInfoPtr->receiveBuffer, length );
	if( cryptStatusError( status ) )
		{
		sendCertErrorResponse( sessionInfoPtr, CRYPT_ERROR_BADDATA );
		retExt( status, 
				( status, SESSION_ERRINFO, "Invalid PKI message encoding" ) );
		}
	sessionInfoPtr->receiveBufEnd = length;

	/* Process the initial message from the client */
	initSCEPprotocolInfo( &protocolInfo );
	status = checkScepRequest( sessionInfoPtr, &protocolInfo, 
							   &requestDataOK );
	if( cryptStatusError( status ) )
		{
		/* If we got far enough into the request data to be able to send a 
		   SCEP-level response, send that, otherwise just send an HTTP-level
		   response */
		if( requestDataOK )
			sendErrorResponse( sessionInfoPtr, &protocolInfo, status );
		else
			sendCertErrorResponse( sessionInfoPtr, status );
		return( status );
		}

	/* Issue a certificate from the request */
	status = issueCertFromRequest( sessionInfoPtr, &protocolInfo );
	if( cryptStatusError( status ) )
		{
		sendErrorResponse( sessionInfoPtr, &protocolInfo, status );
		destroySCEPprotocolInfo( &protocolInfo );
		return( status );
		}

	/* Return the certificate to the client */
	status = createScepResponse( sessionInfoPtr, &protocolInfo );
	if( cryptStatusOK( status ) )
		status = writePkiDatagram( sessionInfoPtr, SCEP_CONTENT_TYPE,
								   SCEP_CONTENT_TYPE_LEN );
	destroySCEPprotocolInfo( &protocolInfo );
	return( status );
	}
Esempio n. 2
0
						 IN_LENGTH const int objectLength,
						 IN_HANDLE const CRYPT_CONTEXT iSignContext,
						 IN_ALGO const CRYPT_ALGO_TYPE hashAlgo,
						 IN_OPT const X509SIG_FORMATINFO *formatInfo )
	{
	CRYPT_CONTEXT iHashContext;
	MESSAGE_CREATEOBJECT_INFO createInfo;
	STREAM stream;
	BYTE dataSignature[ CRYPT_MAX_PKCSIZE + 128 + 8 ];
	int signatureLength, totalSigLength, status;

	assert( signedObject == NULL || \
			isWritePtr( signedObject, signedObjectMaxLength ) );
	assert( isWritePtr( signedObjectLength, sizeof( int ) ) );
	assert( isReadPtr( object, objectLength ) && \
			!cryptStatusError( checkObjectEncoding( object, \
													objectLength ) ) );
	assert( formatInfo == NULL || \
			isReadPtr( formatInfo, sizeof( X509SIG_FORMATINFO ) ) );

	REQUIRES( ( signedObject == NULL && signedObjectMaxLength == 0 ) || \
			  ( signedObject != NULL && \
				signedObjectMaxLength > MIN_CRYPT_OBJECTSIZE && \
				signedObjectMaxLength < MAX_INTLENGTH ) );
	REQUIRES( objectLength > 0 && objectLength < MAX_INTLENGTH );
	REQUIRES( isHandleRangeValid( iSignContext ) );
	REQUIRES( isHashAlgo( hashAlgo ) );
	REQUIRES( formatInfo == NULL || \
			  ( ( formatInfo->tag >= 0 && \
				  formatInfo->tag < MAX_CTAG_VALUE ) && \
				( formatInfo->extraLength >= 0 && \
				  formatInfo->extraLength < MAX_INTLENGTH_SHORT ) ) );