Example #1
0
static int processAdditionalScepRequest( INOUT SESSION_INFO *sessionInfoPtr,
										 const HTTP_URI_INFO *httpReqInfo )
	{
	HTTP_URI_INFO rewrittenHttpReqInfo;
	MESSAGE_DATA msgData;
	int operationType, status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isReadPtr( httpReqInfo, sizeof( HTTP_URI_INFO ) ) );

	/* If the client has fed us an HTTP GET request, find out what they  
	   want.  SCEP's handling of HTTP requests is a bit different from the 
	   "attribute '=' value" lookup that's normally used for HTTP data 
	   retrieval.  Instead, it uses the format 
	   "'operation =' value '&' extraData", with the search key buried in 
	   the 'extraData' value.  In addition the content of the 'extraData' 
	   value isn't defined outside of "any string which is understood by the 
	   CA".  However since 'value' defines what we want, we can determine 
	   what to return based on this and ignore the 'extraData' portion.

	   In order to fix up the query information into a format that works 
	   with standard HTTP queries, we rewrite the query data from the 
	   "'operation =' value '&' extraData" form into "attribute '=' value" 
	   before we process the query */
	memset( &rewrittenHttpReqInfo, 0, sizeof( HTTP_URI_INFO ) );
	memcpy( rewrittenHttpReqInfo.attribute, httpReqInfo->value, 
			httpReqInfo->valueLen );
	rewrittenHttpReqInfo.attributeLen = httpReqInfo->valueLen;
	if( httpReqInfo->extraDataLen > 0 )
		{
		memcpy( rewrittenHttpReqInfo.value, httpReqInfo->extraData, 
				httpReqInfo->extraDataLen );
		rewrittenHttpReqInfo.valueLen = httpReqInfo->extraDataLen;
		}
	status = processCertQuery( sessionInfoPtr, &rewrittenHttpReqInfo,
							   certstoreReadInfo, 
							   FAILSAFE_ARRAYSIZE( certstoreReadInfo, \
												   CERTSTORE_READ_INFO ),
							   &operationType, NULL, 0, NULL );
	if( cryptStatusError( status ) )
		{
		sendCertErrorResponse( sessionInfoPtr, status );
		return( status );
		}
	ENSURES( operationType == SCEP_OPERATION_GETCACAPS || \
			 operationType == SCEP_OPERATION_GETCACERT || \
			 operationType == SCEP_OPERATION_GETCACERTCHAIN );

	/* If it's a CA capabilities query, return the information as raw text
	   over HTTP */
	if( operationType == SCEP_OPERATION_GETCACAPS )
		{
		STREAM stream;

		sMemOpen( &stream, sessionInfoPtr->receiveBuffer, 1024 );
		swrite( &stream, "POSTPKIOperation\n", 17 );
#if 0	/* 14/6/14 Too risky to implement given its current state in the 
				   spec, see the discussion on the JSCEP mailing list for
				   details */
		status = swrite( &stream, "Renewal\n", 8 );
#endif /* 0 */
		if( algoAvailable( CRYPT_ALGO_SHA1 ) )
			status = swrite( &stream, "SHA-1\n", 6 );
		if( algoAvailable( CRYPT_ALGO_SHA2 ) )
			status = swrite( &stream, "SHA-256\n", 8 );
		if( algoAvailable( CRYPT_ALGO_SHAng ) )
			status = swrite( &stream, "SHAng\n", 6 );
		if( algoAvailable( CRYPT_ALGO_3DES ) )
			status = swrite( &stream, "DES3\n", 5 );
		if( algoAvailable( CRYPT_ALGO_AES ) )
			status = swrite( &stream, "AES\n", 4 );
		if( cryptStatusOK( status ) )
			sessionInfoPtr->receiveBufEnd = stell( &stream );
		sMemDisconnect( &stream );
		ENSURES( cryptStatusOK( status ) );
		return( writePkiDatagram( sessionInfoPtr, SCEP_CONTENT_TYPE, 
								  SCEP_CONTENT_TYPE_LEN ) );
		}
static int processAdditionalScepRequest( INOUT SESSION_INFO *sessionInfoPtr,
										 const HTTP_URI_INFO *httpReqInfo )
	{
	HTTP_URI_INFO rewrittenHttpReqInfo;
	MESSAGE_DATA msgData;
	int operationType, status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isReadPtr( httpReqInfo, sizeof( HTTP_URI_INFO ) ) );

	/* If the client has fed us an HTTP GET request, find out what they  
	   want.  SCEP's handling of HTTP requests is a bit different from the 
	   "attribute '=' value" lookup that's normally used for HTTP data 
	   retrieval.  Instead, it uses the format 
	   "'operation =' value '&' extraData", with the search key buried in 
	   the 'extraData' value.  In addition the content of the 'extraData' 
	   value isn't defined outside of "any string which is understood by the 
	   CA".  However since 'value' defines what we want, we can determine 
	   what to return based on this and ignore the 'extraData' portion.

	   In order to fix up the query information into a format that works 
	   with standard HTTP queries, we rewrite the query data from the 
	   "'operation =' value '&' extraData" form into "attribute '=' value" 
	   before we process the query */
	memset( &rewrittenHttpReqInfo, 0, sizeof( HTTP_URI_INFO ) );
	memcpy( rewrittenHttpReqInfo.attribute, httpReqInfo->value, 
			httpReqInfo->valueLen );
	rewrittenHttpReqInfo.attributeLen = httpReqInfo->valueLen;
	if( httpReqInfo->extraDataLen > 0 )
		{
		memcpy( rewrittenHttpReqInfo.value, httpReqInfo->extraData, 
				httpReqInfo->extraDataLen );
		rewrittenHttpReqInfo.valueLen = httpReqInfo->extraDataLen;
		}
	status = processCertQuery( sessionInfoPtr, &rewrittenHttpReqInfo,
							   certstoreReadInfo, 
							   FAILSAFE_ARRAYSIZE( certstoreReadInfo, \
												   CERTSTORE_READ_INFO ),
							   &operationType, NULL, 0, NULL );
	if( cryptStatusError( status ) )
		{
		sendCertErrorResponse( sessionInfoPtr, status );
		return( status );
		}
	ENSURES( operationType == SCEP_OPERATION_GETCACAPS || \
			 operationType == SCEP_OPERATION_GETCACERT || \
			 operationType == SCEP_OPERATION_GETCACERTCHAIN );

	/* If it's a CA capabilities query, return the information as raw text
	   over HTTP */
	if( operationType == SCEP_OPERATION_GETCACAPS )
		{
		STREAM stream;

		sMemOpen( &stream, sessionInfoPtr->receiveBuffer, 1024 );
		status = swrite( &stream, "POSTPKIOperation\n", 17 );
		if( algoAvailable( CRYPT_ALGO_SHA1 ) )
			status = swrite( &stream, "SHA-1\n", 6 );
		if( algoAvailable( CRYPT_ALGO_SHA2 ) )
			status = swrite( &stream, "SHA-256\n", 8 );
		if( algoAvailable( CRYPT_ALGO_SHAng ) )
			status = swrite( &stream, "SHAng\n", 6 );
		if( algoAvailable( CRYPT_ALGO_3DES ) )
			status = swrite( &stream, "DES3\n", 5 );
		if( algoAvailable( CRYPT_ALGO_AES ) )
			status = swrite( &stream, "AES\n", 4 );
		if( cryptStatusOK( status ) )
			sessionInfoPtr->receiveBufEnd = stell( &stream );
		sMemDisconnect( &stream );
		ENSURES( cryptStatusOK( status ) );
		return( writePkiDatagram( sessionInfoPtr, SCEP_CONTENT_TYPE,
								  SCEP_CONTENT_TYPE_LEN ) );
		}

	/* Export the CA certificate and send it to the client */
	setMessageData( &msgData, sessionInfoPtr->receiveBuffer,
					sessionInfoPtr->receiveBufSize );
	status = krnlSendMessage( sessionInfoPtr->privateKey,
							  IMESSAGE_CRT_EXPORT, &msgData,
							  ( operationType == SCEP_OPERATION_GETCACERT ) ? \
								CRYPT_CERTFORMAT_CERTIFICATE : \
								CRYPT_CERTFORMAT_CERTCHAIN );
	if( cryptStatusError( status ) )
		{
		retExt( status,
				( status, SESSION_ERRINFO, 
				  "Couldn't export CA certificate%s for '%s' request", 
				  ( operationType == SCEP_OPERATION_GETCACERT ) ? \
					"" : " chain",
				  ( operationType == SCEP_OPERATION_GETCACERT ) ? \
					"GetCACert" : "GetCACertChain" ) );
		}
	sessionInfoPtr->receiveBufEnd = msgData.length;
	if( operationType == SCEP_OPERATION_GETCACERT )
		{
		return( writePkiDatagram( sessionInfoPtr, 
								  SCEP_CONTENT_TYPE_GETCACERT,
								  SCEP_CONTENT_TYPE_GETCACERT_LEN ) );
		}
	return( writePkiDatagram( sessionInfoPtr, 
							  SCEP_CONTENT_TYPE_GETCACERTCHAIN,
							  SCEP_CONTENT_TYPE_GETCACERTCHAIN_LEN ) );
	}
Example #3
0
static int writeCertRequest( INOUT SESSION_INFO *sessionInfoPtr, 
							 INOUT SSL_HANDSHAKE_INFO *handshakeInfo,
							 INOUT STREAM *stream )
	{
	const BOOLEAN rsaAvailable = algoAvailable( CRYPT_ALGO_RSA );
	const BOOLEAN dsaAvailable = algoAvailable( CRYPT_ALGO_DSA );
	const BOOLEAN ecdsaAvailable = algoAvailable( CRYPT_ALGO_ECDSA );

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

	REQUIRES( rsaAvailable || ecdsaAvailable );

	/* Write the certificate type */
	sputc( stream, ( rsaAvailable ? 1 : 0 ) + \
				   ( dsaAvailable ? 1 : 0 ) + \
				   ( ecdsaAvailable ? 1 : 0 ) );
	if( rsaAvailable )
		sputc( stream, TLS_CERTTYPE_RSA );
	if( dsaAvailable )
		sputc( stream, TLS_CERTTYPE_DSA );
	if( ecdsaAvailable )
		sputc( stream, TLS_CERTTYPE_ECDSA );

	/* Write the list of accepted signature and hash algorithms if required.  
	   In theory we could write the full list of algorithms, but thanks to 
	   SSL/TLS' braindamaged way of handling certificate-based 
	   authentication (see the comment above) this would make the 
	   certificate-authentication process unmanageable.  To get around this 
	   we only allow one single algorithm, the SHA-2 default for TLS 1.2+.  
	   In addition we can't allow DSA because it's only defined for use with 
	   SHA-1 (unless we go for "DSA-2" / FIPS 186-3 key sizes like 2048 
	   bits, which nothing seems to support).

	   For Suite B things get a bit more complicated because this allows 
	   both SHA-256 and SHA-384, dropping us straight back into the mess 
	   that we've just escaped from.  To get around this we specify the
	   use of the hash algorithm that we've negotiated for the handshake,
	   on the assumption that a client using SHA384 for the handshake isn't 
	   going to then try and use SHA256 for the authentication */
	if( sessionInfoPtr->version >= SSL_MINOR_VERSION_TLS12 )
		{
#ifdef CONFIG_SUITEB
		writeUint16( stream, 2 );
		if( handshakeInfo->keyexSigHashAlgoParam == bitsToBytes( 384 ) )
			sputc( stream, TLS_HASHALGO_SHA384 );
		else
			sputc( stream, TLS_HASHALGO_SHA2 );
		sputc( stream, TLS_SIGALGO_ECDSA );
#else
		writeUint16( stream, ( rsaAvailable ? 2 : 0 ) + \
							 ( ecdsaAvailable ? 2 : 0 ) );
		if( rsaAvailable )
			{
			sputc( stream, TLS_HASHALGO_SHA2 );
			sputc( stream, TLS_SIGALGO_RSA );
			}
		if( ecdsaAvailable )
			{
			sputc( stream, TLS_HASHALGO_SHA2 );
			sputc( stream, TLS_SIGALGO_ECDSA );
			}
#endif /* CONFIG_SUITEB */
		}

	/* Write the CA name list */ 
	writeUint16( stream, UINT16_SIZE + 2 );
	writeUint16( stream, 2 );
	return( swrite( stream, "\x30\x00", 2 ) );
	}