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

📄 stream.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 5 页
字号:
		if( localLength > 0 )
			{
			strncpy( stream->errorMessage, bufPtr, 
					 min( localLength, MAX_ERRMSG_SIZE - 1 ) );
			stream->errorMessage[ MAX_ERRMSG_SIZE - 1 ] = '\0';
			}
		else
			strcpy( stream->errorMessage, 
					"Unknown CMP transport-level error encountered" );

		/* The appropriate status values to return for a problem at this 
		   level are pretty unclear, the most appropriate ones appear to be 
		   a read error if there's a problem with the server (exactly what 
		   the problem is is never specified in the error code) and a generic
		   bad data for anything else */
		return( ( ( stream->errorCode & 0x0F00 ) == 0x0300 ) ? \
				CRYPT_ERROR_READ : CRYPT_ERROR_BADDATA );
		}

	return( CRYPT_ERROR_BADDATA );
	}

/* Handle any special handshaking and protocol headers which may be present
   with some network stream types */

static int readProtocolHeader( STREAM *stream, void **bufPtr, int *length, 
							   const int maxLength, const BOOLEAN isServer )
	{
	int localLength = maxLength, status;

	/* Clear return value */
	*length = CRYPT_ERROR;

	/* If it's server tunnelling data over HTTP, read the request header from
	   the client */
	if( isServer && stream->protocol == STREAM_PROTOCOL_HTTP )
		{
		char lineBuffer[ HTTP_LINEBUF_SIZE ];

		/* Read the POST header and check for "POST x HTTP/1.x" */
		status = readLine( stream, lineBuffer );
		if( !cryptStatusError( status ) )
			{
			if( status < 15 || strncmp( lineBuffer, "POST ", 5 ) )
				status = CRYPT_ERROR_BADDATA;
			else
				{
				int i = 4;

				/* Skip ' '* * ' '* */
				while( lineBuffer[ i ] && lineBuffer[ i ] == ' ' )
					i++;
				while( lineBuffer[ i ] && lineBuffer[ i ] != ' ' )
					i++;
				while( lineBuffer[ i ] && lineBuffer[ i ] == ' ' )
					i++;
				if( i > HTTP_LINEBUF_SIZE - 9 || \
					strncmp( lineBuffer + i, "HTTP/1.", 7 ) )
					status = CRYPT_ERROR_READ;
				}
			}
		if( cryptStatusError( status ) )
			return( status );

		/* We've got a valid response, look for a length indicator and skip 
		   any other header lines */
		do
			{
			status = readLine( stream, lineBuffer );
			if( status > 14 && !strncmp( lineBuffer, "Content-Length", 14 ) )
				{
				const char *lengthPos = strchr( lineBuffer, ' ' ) + 1;

				if( lengthPos == NULL )
					status = CRYPT_ERROR_BADDATA;
				else
					{
					/* Make sure the length is sensible.  ~64 bytes is the 
					   minimum-size object which can be returned from any
					   HTTP-based message which is exchanged by cryptlib, 
					   this being a TSP request */
					localLength = atoi( lengthPos );
					if( localLength < 64 )
						status = CRYPT_ERROR_BADDATA;
					else
						if( localLength > maxLength )
							status = CRYPT_ERROR_OVERFLOW;
					}
				}
			}
		while( status > 0 );
		if( cryptStatusError( status ) )
			return( status );
		*length = localLength;
		return( CRYPT_OK );
		}

	/* If it's a fully stateless HTTP read, we need to connect to the server 
	   and send the fetch request before we can read anything */
	if( stream->protocol == STREAM_PROTOCOL_HTTP )
		{
		char headerBuffer[ MAX_URL_SIZE + 128 ];

		assert( stream->netSocket == CRYPT_ERROR );
		assert( stream->protocolState == STREAM_PROTOCOLSTATE_NONE );
		assert( !*stream->contentType );

		/* Open the connection to the remote host */
		status = connectStream( stream );
		if( cryptStatusError( status ) )
			return( status );

		/* Send the HTTP GET header and drop through to reading the 
		   response */
		strcpy( headerBuffer, "GET " );
		strcat( headerBuffer, stream->path );
		if( stream->query != NULL )
			{
			strcat( headerBuffer, "?" );
			strcat( headerBuffer, stream->query );
			}
		strcat( headerBuffer, " HTTP/1.0\r\n\r\n" );
		status = writeSocket( stream, headerBuffer, strlen( headerBuffer ) );
		if( cryptStatusError( status ) )
			return( status );
		stream->protocolState = STREAM_PROTOCOLSTATE_FETCHSENT;
		}

	/* If it's an HTTP read, read the out-of-band header data from the 
	   server */
	if( stream->protocol == STREAM_PROTOCOL_HTTP || \
		stream->protocol == STREAM_PROTOCOL_HTTP_TRANSACTION )
		{
		char lineBuffer[ HTTP_LINEBUF_SIZE ];

		assert( stream->protocolState == STREAM_PROTOCOLSTATE_FETCHSENT );

		/* Read the response header and check for "HTTP/1.x 200" */
		status = readLine( stream, lineBuffer );
		if( !cryptStatusError( status ) )
			{
			if( strncmp( lineBuffer, "HTTP/1.", 7 ) )
				status = CRYPT_ERROR_BADDATA;
			else
				if( strncmp( lineBuffer + 9, "200", 3 ) )
					status = CRYPT_ERROR_READ;
			}
		if( cryptStatusError( status ) )
			return( status );

		/* We've got a valid response, look for a length indicator and skip 
		   any other header lines */
		do
			{
			status = readLine( stream, lineBuffer );
			if( cryptStatusError( status ) )
				return( status );
			if( status > 14 && !strncmp( lineBuffer, "Content-Length", 14 ) )
				{
				const char *lengthPos = strchr( lineBuffer, ' ' ) + 1;

				/* Make sure the length is sensible.  5 bytes is the minimum-
				   size object which can be returned from any HTTP-based 
				   message which is exchanged by cryptlib, this being an 
				   OCSP response containing a single-byte status value, ie 
				   SEQUENCE { ENUM x } */
				if( lengthPos == NULL )
					return( CRYPT_ERROR_BADDATA );
				localLength = atoi( lengthPos );
				if( localLength < 5 )
					return( CRYPT_ERROR_BADDATA );

				/* If there's a buffer-adjust callback present, try and 
				   increase the buffer size */
				if( stream->callbackFunction != NULL )
					{
					int callbackStatus;

					assert( stream->callbackParams != NULL );
					callbackStatus = \
						stream->callbackFunction( stream->callbackParams,
												  bufPtr, localLength );
					if( cryptStatusError( callbackStatus ) )
						return( callbackStatus );
					}
				else
					if( localLength > maxLength )
						return( CRYPT_ERROR_OVERFLOW );
				}
			}
		while( status > 0 );
		*length = localLength;
		stream->protocolState = STREAM_PROTOCOLSTATE_DATAFETCHED;
		return( CRYPT_OK );
		}

	/* If it's a packet-based protocol, read the packet length from the 
	   stream */
	if( stream->protocol == STREAM_PROTOCOL_CMP )
		return( readCmpHeader( stream, length, maxLength ) );

	*length = maxLength;
	return( CRYPT_OK );
	}
#endif /* NET_TCP */

/* OS-specific support routines */

#ifdef __MAC__

static void CStringToPString( const char *cstring, StringPtr pstring )
	{
	short len = min( strlen( cstring ), 255 );

	memmove( pstring+1, cstring, len );
	*pstring = len;
	}
#endif /* __MAC__ */

/****************************************************************************
*																			*
*							Generic Stream I/O Functions					*
*																			*
****************************************************************************/

/* Read a byte from a stream */

int sgetc( STREAM *stream )
	{
#if defined( __WIN32__ )
	DWORD bytesRead;
	BYTE ch;
#elif defined( __MAC__ )
	long bytesRead = 1;
	BYTE ch;
#else
	int ch;
#endif /* OS-specific variable declarations */

	assert( stream != NULL && \
			( stream->type == STREAM_TYPE_MEMORY || \
			  stream->type == STREAM_TYPE_FILE ) );

	/* If there's a problem with the stream, don't try to do anything */
	if( stream->status != CRYPT_OK )
		return( stream->status );

	/* If we ungot a char, return this */
	if( stream->ungetChar )
		{
		ch = stream->lastChar;
		stream->ungetChar = FALSE;
		return( ch );
		}

	/* If it's a memory stream, read the data from the buffer */
	if( stream->type == STREAM_TYPE_MEMORY )
		{
		if( stream->bufSize != STREAMSIZE_UNKNOWN && \
			stream->bufPos >= stream->bufEnd )
			{
			stream->status = CRYPT_ERROR_UNDERFLOW;
			return( CRYPT_ERROR_UNDERFLOW );
			}
		stream->lastChar = stream->buffer[ stream->bufPos++ ];

		return( stream->lastChar );
		}

#ifndef NO_STDIO
	/* It's a file stream, read the data from the file */
#if defined( __WIN32__ )
	if( !ReadFile( stream->hFile, &ch, 1, &bytesRead, NULL ) || !bytesRead )
#elif defined( __MAC__ )
	if( FSRead( stream->refNum, &bytesRead, &ch) != noErr || !bytesRead )
#else
	if( ( ch = getc( stream->filePtr ) ) == EOF )
#endif /* __WIN32__ */
		{
		stream->status = CRYPT_ERROR_UNDERFLOW;
		return( CRYPT_ERROR_UNDERFLOW );
		}
#else
	assert( NOTREACHED );
#endif /* NO_STDIO */

	return( stream->lastChar = ch );
	}

/* Write a byte to a stream */

int sputc( STREAM *stream, int data )
	{
#if defined( __WIN32__ )
	DWORD bytesWritten;
	const BYTE byteData = data;
#elif defined( __MAC__ )
	long bytesWritten = 1;
	const BYTE byteData = data;
#endif /* Win32 || Macintosh */

	assert( stream != NULL );
	assert( stream->type == STREAM_TYPE_NULL || \
			stream->type == STREAM_TYPE_MEMORY || \
			stream->type == STREAM_TYPE_FILE );
	assert( !( stream->flags & STREAM_FLAG_READONLY ) );

	/* If there's a problem with the stream, don't try to do anything until
	   the error is cleared */
	if( stream->status != CRYPT_OK )
		return( stream->status );

	/* If it's a null stream, just record the write and return */
	if( stream->type == STREAM_TYPE_NULL )
		{
		stream->bufPos++;
		return( CRYPT_OK );
		}

	/* If we ungot a char, move back one entry in the buffer */
	if( stream->ungetChar && stream->bufPos )
		{
		stream->bufPos--;
		stream->ungetChar = FALSE;
		}

	/* If it's a memory stream, deposit the data in the buffer */
	if( stream->type == STREAM_TYPE_MEMORY )
		{
		if( stream->bufSize != STREAMSIZE_UNKNOWN && \
			stream->bufPos >= stream->bufSize )
			{
#ifdef NO_STDIO
			/* If it's a non-sensitive pseudo-I/O stream, expand the buffer */
			if( stream->isIOStream && !stream->isSensitive )
				{
				const int status = expandBuffer( stream, 1 );
				if( cryptStatusError( status ) )
					return( status );
				}
			else
#endif /* NO_STDIO */
				{
				stream->status = CRYPT_ERROR_OVERFLOW;
				return( CRYPT_ERROR_OVERFLOW );
				}
			}
		stream->buffer[ stream->bufPos++ ] = data;
		if( stream->bufEnd < stream->bufPos )
			/* Move up the end-of-data pointer if necessary */
			stream->bufEnd = stream->bufPos;
		stream->flags |= STREAM_FLAG_DIRTY;

		return( CRYPT_OK );
		}

#ifndef NO_STDIO
	/* It's a file stream, write the data to the file */
#if defined( __WIN32__ )
	if( !WriteFile( stream->hFile, &byteData, 1, &bytesWritten, NULL ) || \
		!bytesWritten )
#elif defined( __MAC__ )
	if( FSWrite( stream->refNum, &bytesWritten, &byteData ) != noErr || \
		!bytesWritten )
#else
	if( putc( data, stream->filePtr ) == EOF )
#endif /* __WIN32__ */
		{
		stream->status = CRYPT_ERROR_WRITE;
		return( CRYPT_ERROR_WRITE );
		}
	stream->flags |= STREAM_FLAG_DIRTY;
#else
	assert( NOTREACHED );
#endif /* NO_STDIO */

	return( CRYPT_OK );
	}

/* Unget a byte from a stream */

int sungetc( STREAM *stream )
	{
	assert( stream != NULL && \
			( stream->type == STREAM_TYPE_NULL || \
			  stream->type == STREAM_TYPE_MEMORY || \
			  stream->type == STREAM_TYPE_FILE ) );

	/* If the stream is empty, calling this function resets the stream
	   status to nonempty (since we can't read past EOF, ungetting even one
	   char will reset the stream status).  If the stream isn't empty, we
	   set a flag to indicate that we should return the last character read
	   in the next read call */
	if( stream->status == CRYPT_ERROR_UNDERFLOW )
		stream->status = CRYPT_OK;
	else
		stream->ungetChar = TRUE;

	return( CRYPT_OK );
	}

/* Read a block of data from a stream.  If not enough data is available it
   will fail with CRYPT_ERROR_UNDERFLOW rather than trying to read as much
   as it can, which mirrors the behaviour of most read()/fread()
   implementations, however with some higher-level network protocols we don't
   know the data length in advance so we specify the maximum length which
   we're prepared to accept and let sread() sort out the details */

⌨️ 快捷键说明

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