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

📄 cryptmis.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 3 页
字号:
#define BINARY_LINESIZE	48

/* Basic single-char en/decode functions */

#define encode(data)	binToAscii[ data ]
#define decode(data)	asciiToBin[ data ]

/* The headers and trailers used for base64-encoded certificate objects.
   Since the zero-th value is a non-value, we include a dummy entry at the
   start */

static const char *headerTbl[] = {
	NULL,
	"-----BEGIN CERTIFICATE-----" EOL,
	"-----BEGIN ATTRIBUTE CERTIFICATE-----" EOL,
	"-----BEGIN CERTIFICATE CHAIN-----" EOL,
	"-----BEGIN NEW CERTIFICATE REQUEST-----" EOL,
	"-----BEGIN CRL-----"  EOL
	};
static const char *trailerTbl[] = {
	NULL,
	"-----END CERTIFICATE-----" EOL,
	"-----END ATTRIBUTE CERTIFICATE-----" EOL,
	"-----END CERTIFICATE CHAIN-----" EOL,
	"-----END NEW CERTIFICATE REQUEST-----" EOL,
	"-----END CRL-----" EOL
	};

/* Check whether a data item has a header which identifies it as some form of
   PEM-style encoded certificate object and return the start position of the
   encoded data.  Since there are so many variants possible, we don't perform
   a very strict check because there'll always be some new variants which
   isn't handled.  The exact object type can be determined by the lower-level
   routines */

int base64checkHeader( const char *data, const int dataLength )
	{
	STREAM stream;
	char buffer[ 64 ];
	int ch, i;

	sMemConnect( &stream, data, dataLength );

	/* Sometimes the object can be preceded by a few blank lines - we're
	   fairly lenient with this */
	do
		ch = sgetc( &stream );
	while( ch == '\r' || ch == '\n' );
	buffer[ 0 ] = ch;

	/* We always have to start with 5 dashes and 'BEGIN '.  After this there
	   can be all sorts of stuff, but it has to end with another five dashes
	   and a newline */
	if( cryptStatusError( sread( &stream, buffer + 1, 10 ) ) || \
		memcmp( buffer, "-----BEGIN ", 11 ) )
		{
		sMemDisconnect( &stream );
		return( 0 );
		}
	for( i = 0; i < 40; i++ )
		if( sgetc( &stream ) == '-' )
			break;
	if( i == 40 )
		{
		sMemDisconnect( &stream );
		return( 0 );
		}
	if( cryptStatusError( sread( &stream, buffer, 4 ) ) || \
		memcmp( buffer, "----", 4 ) )
		{
		sMemDisconnect( &stream );
		return( 0 );
		}
	ch = sgetc( &stream );
	if( ch != '\n' )
		{
		if( ch == '\r' )
			{
			if( sgetc( &stream ) != '\n' )
				sungetc( &stream );
			}
		else
			{
			sMemDisconnect( &stream );
			return( 0 );
			}
		}

	/* Return the start position of the payload */
	i = stell( &stream );
	sMemDisconnect( &stream );
	return( cryptStatusError( i ) ? 0 : i );
	}

/* Check whether a data item has a header which identifies it as some form of
   S/MIME certificate data.  This gets quite complex because there are many
   possible variations in the headers.  Some early S/MIME agents used a
   content type of "application/x-pkcs7-mime",
   "application/x-pkcs7-signature", and "application/x-pkcs10", while newer
   ones use the same without the "x-" at the start.  Older agents would put
   the filename in the Content-Type "name" parameter while newer ones put it
   in the optional Content-Disposition "filename" parameter (actually for
   backwards-compatibility most newer ones tend to include both).  The
   Content-Description is optional.  The general header format (all
   whitespace is optional) is:

	Content-Type: application/{x-} \
		pkcs7-mime{; name=|; smime-type= \
					 enveloped-data|signed-data|certs-only}
		pkcs7-signature{; name=}
		pkcs10{; name=}
	Content-Disposition: attachment{; filename=}
	Content-Transfer-Encoding: base64
	Content-Description: S/MIME {Cryptographic Signature|???}

   The result is that we have to create a somewhat nontrivial parser to
   handle all the variations.

   In addition Netscape have their own MIME data types for certificates:

	Content-Type: application/x-x509-{user-cert|ca-cert|email-cert}

   (probably with other bits as well, details unknown) which we also handle,
   although the exact cert type is ignored since it's up to the cert handling
   routines to sort this out via authenticated attributes rather than using
   the unauthenticated MIME content type */

/* Various nonspecific parsing routines */

static void skipWhitespace( STREAM *stream )
	{
	int ch;

	do
		ch = sgetc( stream );
	while( ch == ' ' || ch == '\t' );
	sungetc( stream );
	}

static void skipEOL( STREAM *stream )
	{
	int ch;

	/* Skip a LF or CR with optional LF */
	ch = sgetc( stream );
	if( ch == '\n' )
		return;
	if( ch == '\r' && \
		sgetc( stream ) == '\n' )
		return;
	sungetc( stream );
	}

static BOOLEAN skipToNextToken( STREAM *stream )
	{
	int ch = sgetc( stream );

	/* If this is the end of the line, don't to anything */
	if( ch == '\r' || ch == '\n' )
		{
		sungetc( stream );
		return( TRUE );
		}

	/* Skip to the start of the next token after the current one.  This
	   parses ";{ }{EOL }}" */
	if( ch != ';' )
		return( FALSE );
	skipWhitespace( stream );
	ch = sgetc( stream );
	if( ch != '\r' && ch != '\n' )
		{
		sungetc( stream );
		return( TRUE );
		}
	skipEOL( stream );		/* Line is continued, skip EOL and whitespace */
	ch = sgetc( stream );
	if( ch != ' ' && ch != '\t' )
		return( FALSE );	/* Should have whitespace after continuation */
	skipWhitespace( stream );

	return( TRUE );
	}

static BOOLEAN skipCurrentToken( STREAM *stream )
	{
	BOOLEAN isQuoted = FALSE;
	int ch = sgetc( stream );

	while( ch != '\n' && ch != '\r' )
		{
		if( !isQuoted && ch == ';' )
			{
			/* If we reach an unquoted semicolon, we're at the end of the
			   token */
			sungetc( stream );
			return( skipToNextToken( stream ) );
			}
		if( ch == '"' )
			isQuoted = !isQuoted;
		ch = sgetc( stream );
		}
	sungetc( stream );

	return( isQuoted ? FALSE : skipToNextToken( stream ) );
	}

static BOOLEAN skipLine( STREAM *stream )
	{
	BOOLEAN continuation;
	int ch = sgetc( stream );

	/* MIME headers can be continued over multiple lines.  If there's a
	   semicolon at the end of the current line, we continue to the next
	   one */
	do
		{
		continuation = FALSE;
		while( ch != '\r' && ch != '\n' )
			{
			if( ( ch & 0x7F ) < ' ' )
			continuation = ( ch == ';' );
			ch = sgetc( stream );
			}
		if( continuation )
			{
			sungetc( stream );
			if( !skipToNextToken( stream ) )
				return( FALSE );
			ch = sgetc( stream );
			}
		}
	while( continuation );
	sungetc( stream );

	/* Check for a single EOL */
	skipEOL( stream );
	return( TRUE );
	}

/* Parse the various MIME header lines */

static BOOLEAN parseContentType( STREAM *stream )
	{
	char buffer[ 64 ];
	int ch;

	/* Look for "application/{x-}pkcs{7-mime|7-signature|10}" */
	skipWhitespace( stream );
	if( cryptStatusError( sread( stream, buffer, 12 ) ) || \
		memcmp( buffer, "application/", 12 ) )
		return( FALSE );
	if( sgetc( stream ) == 'x' )
		{
		/* Skip old-style "x-" header */
		if( sgetc( stream ) != '-' )
			return( FALSE );
		
		/* Check for one of the Netscape cert types */
		if( sgetc( stream ) == 'x' )
			{
			/* "x509-"*/
			if( cryptStatusError( sread( stream, buffer, 4 ) ) || \
				memcmp( buffer, "509-", 4 ) )
				return( FALSE );
			return( skipLine( stream ) );
			}
		sungetc( stream );
		}
	else
		sungetc( stream );
	if( cryptStatusError( sread( stream, buffer, 4 ) ) || \
		memcmp( buffer, "pkcs", 4 ) )
		return( FALSE );
	ch = sgetc( stream );
	if( ch == '7' )
		{
		if( sgetc( stream ) != '-' )
			return( FALSE );
		ch = sgetc( stream );
		if( ch != 'm' && ch != 's' )
			return( FALSE );
		if( ch == 'm' )
			{
			/* "pkcs7-mime" */
			if( cryptStatusError( sread( stream, buffer, 4 ) ) || \
				memcmp( buffer, "mime", 4 ) )
				return( FALSE );
			}
		else
			/* "pkcs7-signature" */
			if( cryptStatusError( sread( stream, buffer, 8 ) ) || \
				memcmp( buffer, "ignature", 8 ) )
				return( FALSE );
		}
	else
		if( ch == '1' )
			{
			/* "pkcs10" */
			if( sgetc( stream ) != '0' )
				return( FALSE );
			}
		else
			return( FALSE );
	if( !skipToNextToken( stream ) )
		return( FALSE );
	ch = sgetc( stream );
	if( ch == '\n' || ch == '\r' )
		{
		/* If that's all there is, return */
		sungetc( stream );
		skipEOL( stream );
		return( TRUE );
		}

	/* Check for an optional old-style name attribute */
	if( ch == 'n' )
		{
		/* name= */
		if( cryptStatusError( sread( stream, buffer, 4 ) ) || \
			memcmp( buffer, "ame=", 4 ) )
			return( FALSE );
		skipWhitespace( stream );
		if( !skipCurrentToken( stream ) )
			return( FALSE );
		ch = sgetc( stream );
		sungetc( stream );
		if( ch == '\n' || ch == '\r' )
			{
			/* If that's all there is, return */
			skipEOL( stream );
			return( TRUE );
			}
		}

	/* Check for an SMIME type */
	if( cryptStatusError( sread( stream, buffer, 11 ) ) || \
		memcmp( buffer, "smime-type=", 11 ) )
		return( FALSE );
	skipWhitespace( stream );
	ch = sgetc( stream );
	if( ch == 's' )
		{
		/* signed-data */
		if( cryptStatusError( sread( stream, buffer, 10 ) ) || \
			memcmp( buffer, "igned-data", 10 ) )
			return( FALSE );
		}
	else
		{
		/* certs-only */
		if( ch != 'c' )
			return( FALSE );
		if( cryptStatusError( sread( stream, buffer, 9 ) ) || \
			memcmp( buffer, "erts-only", 9 ) )
			return( FALSE );
		}

	return( skipLine( stream ) );
	}

static BOOLEAN parseContentDisposition( STREAM *stream )
	{
	char buffer[ 64 ];
	int ch;

	/* Look for "attachment" */
	skipWhitespace( stream );
	ch = sgetc( stream );
	if( ch == 'a' )
		{
		/* attachment */
		if( cryptStatusError( sread( stream, buffer, 9 ) ) || \
			memcmp( buffer, "ttachment", 9 ) )
			return( FALSE );
		}
	else
		{
		/* inline */
		if( ch != 'i' )
			return( FALSE );
		if( cryptStatusError( sread( stream, buffer, 5 ) ) || \
			memcmp( buffer, "nline", 5 ) )
			return( FALSE );
		}
	return( TRUE );
	}

static BOOLEAN parseContentTransferEncoding( STREAM *stream )
	{
	char buffer[ 64 ];

	/* Look for "base64" */
	skipWhitespace( stream );
	if( cryptStatusError( sread( stream, buffer, 6 ) ) || \
		memcmp( buffer, "base64", 6 ) )
		return( FALSE );
	return( skipLine( stream ) );
	}

/* Check an S/MIME header.  Returns the length of the header */

int smimeCheckHeader( const char *data, const int dataLength )
	{
	STREAM stream;
	BOOLEAN seenType = FALSE, seenDisposition = FALSE;
	BOOLEAN seenDescription = FALSE, seenTransferEncoding = FALSE;
	BOOLEAN dataOK = TRUE;
	char buffer[ 64 ];
	int ch;

	sMemConnect( &stream, data, dataLength );

	/* Sometimes the object can be preceded by a few blank lines - we're
	   fairly lenient with this */
	do
		ch = sgetc( &stream );
	while( ch == '\r' || ch == '\n' );

	/* Make sure there's a MIME content-type header there */
	if( ch != 'C' )
		{
		sMemDisconnect( &stream );
		return( 0 );
		}
	while( ch != '\r' && ch != '\n' )
		{
		/* Check for the different types of content header which are
		   allowed */
		if( cryptStatusError( sread( &stream, buffer, 7 ) ) || \
			memcmp( buffer, "ontent-", 7 ) )
			dataOK = FALSE;
		ch = sgetc( &stream );
		if( ch != 'D' && ch != 'T' )
			dataOK = FALSE;
		if( ch == 'D' )
			{
			ch = sgetc( &stream );
			if( ch == 'i' )
				{
				/* "Disposition:" */
				if( cryptStatusError( sread( &stream, buffer, 10 ) ) || \
					memcmp( buffer, "sposition:", 10 ) || seenDisposition )
					dataOK = FALSE;
				seenDisposition = TRUE;
				if( dataOK )
					dataOK = parseContentDisposition( &stream );
				}
			else
				{
				/* "Description:" */
				if( ch != 'e' )
					dataOK = FALSE;
				if( cryptStatusError( sread( &stream, buffer, 10 ) ) || \
					memcmp( buffer, "scription:", 10 ) || seenDescription )
					dataOK = FALSE;
				seenDescription = TRUE;
				if( dataOK )
					dataOK = skipLine( &stream );
				}
			}
		else
			{
			ch = sgetc( &stream );
			if( ch == 'y' )
				{
				/* "Type:" */
				if( cryptStatusError( sread( &stream, buffer, 4 ) ) || \
					memcmp( buffer, "ype:", 4 ) || seenType )
					dataOK = FALSE;
				seenType = TRUE;
				if( dataOK )
					dataOK = parseContentType( &stream );
				}
			else
				{
				/* "Transfer-Encoding:" */
				if( ch != 'r' )
					dataOK = FALSE;
				if( cryptStatusError( sread( &stream, buffer, 16 ) ) || \
					memcmp( buffer, "ansfer-Encoding:", 16 ) || \
					seenTransferEncoding )
					dataOK = FALSE;
				seenTransferEncoding = TRUE;
				if( dataOK )
					dataOK = parseContentTransferEncoding( &stream );
				}
			}

⌨️ 快捷键说明

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