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

📄 certstr.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************
*																			*
*							Certificate String Routines						*
*						Copyright Peter Gutmann 1996-2003					*
*																			*
****************************************************************************/

#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL ) ||  defined( INC_CHILD )
  #include "cert.h"
  #include "../misc/asn1_rw.h"
#else
  #include "cert/cert.h"
  #include "misc/asn1_rw.h"
#endif /* Compiler-specific includes */

/****************************************************************************
*																			*
*						Character Set Management Functions					*
*																			*
****************************************************************************/

/* The character set (or at least ASN.1 string type) for a string.  Although 
   IA5String and VisibleString/ISO646String are technically different, the 
   only real difference is that IA5String allows the full range of control 
   characters, which isn't notably useful.  For this reason we treat both as 
   ISO646String.  Sometimes we can be fed Unicode strings that are just 
   bloated versions of another string type, so we need to account for these 
   as well.

   UTF-8 strings are a pain because they're not supported as any native
   format and almost anything they can do is covered by another character 
   set.  For this reason we currently convert them to a more useful set 
   (ASCII, 8859-1, or Unicode as appropriate) to make them usable.  UTF-8 
   strings are currently, never written, although they'll be required after
   the PKIX cutover date of December 2003.  It'll be interesting to see how
   much software breaks with these strings */

typedef enum {
	STRINGTYPE_NONE,					/* No string type */

	/* 8-bit character types */
	STRINGTYPE_PRINTABLE,				/* PrintableString */
	STRINGTYPE_IA5,						/* IA5String */
		STRINGTYPE_VISIBLE = STRINGTYPE_IA5,	/* VisibleString */
										/* VisibleString as Unicode */
	STRINGTYPE_T61,						/* T61 (8859-1) string */

	/* 8-bit types masquerading as Unicode */
	STRINGTYPE_UNICODE_PRINTABLE,		/* PrintableString as Unicode */
	STRINGTYPE_UNICODE_IA5,				/* IA5String as Unicode */
		STRINGTYPE_UNICODE_VISIBLE = STRINGTYPE_UNICODE_IA5,
	STRINGTYPE_UNICODE_T61,				/* 8859-1 as Unicode */

	/* Unicode/UTF-8 */
	STRINGTYPE_UNICODE,					/* Unicode string */
	STRINGTYPE_UTF8						/* UTF-8 string (never written) */
	} ASN1_STRINGTYPE;

/* Since wchar_t can be anything from 8 bits (Borland C++ under DOS) to 64 
   bits (RISC Unixen), we define a bmpchar_t for Unicode/BMPString chars 
   which is always 16 bits as required for BMPStrings, to match wchar_t.  
   The conversion to and from a BMPString and wchar_t may require narrowing 
   or widening of characters, and possibly endianness conversion as well */

typedef unsigned short int bmpchar_t;	/* Unicode data type */
#define UCSIZE	2

/* Because of the bizarre (and mostly useless) collection of ASN.1 character
   types, we need to be very careful about what we allow in a string.  The
   following table is used to determine whether a character is valid within
   certain string types.

   Although IA5String and VisibleString/ISO646String are technically
   different, the only real difference is that IA5String allows the full
   range of control characters, which isn't notably useful.  For this reason
   we treat both as ISO646String */

#define P	1						/* PrintableString */
#define I	2						/* IA5String/VisibleString/ISO646String */
#define PI	( P | I )				/* PrintableString and IA5String */

static const FAR_BSS int asn1CharFlags[] = {
	/* 00  01  02  03  04  05  06  07  08  09  0A  0B  0C  0D  0E  0F */
		0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,
	/* 10  11  12  13  14  15  16  17  18  19  1A  1B  1C  1D  1E  1F */
		0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,	0,
	/*		!	"	#	$	%	&	'	(	)	*	+	,	-	.	/ */
	   PI,	I,	I,	I,	I,	I,	I, PI, PI, PI,	I, PI, PI, PI, PI, PI,
	/*	0	1	2	3	4	5	6	7	8	9	:	;	<	=	>	? */
	   PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI,	I,	I, PI,	I, PI,
	/*	@	A	B	C	D	E	F	G	H	I	J	K	L	M	N	O */
		I, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI,
	/*	P	Q	R	S	T	U	V	W	X	Y	Z	[	\	]	^	_ */
	   PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI,	I,	I,	I,	I,	I,
	/*	`	a	b	c	d	e	f	g	h	i	j	k	l	m	n	o */
		I, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI,
	/*	p	q	r	s	t	u	v	w	x	y	z	{	|	}	~  DL */
	   PI, PI, PI, PI, PI, PI, PI, PI, PI, PI, PI,	I,	I,	I,	I,	0
	};

#define nativeCharFlags	asn1CharFlags

/* Try and guess whether a native string is a widechar string */

static BOOLEAN isNativeWidecharString( const BYTE *string, const int length )
	{
	wchar_t *wcString = ( wchar_t * ) string;
	int hiByte = 0, i;

	assert( !( length % WCSIZE ) );

	/* If it's too short to be a widechar string, it's definitely not 
	   Unicode */
	if( length < WCSIZE )
		/* "Too skinny to join the army they said.  Didn't make the weight
		    they said" */
		return( FALSE );

	/* If wchar_t is > 16 bits and the bits above 16 are set or all zero,
	   it's either definitely not Unicode or Unicode */
#if INT_MAX > 0xFFFFL
	if( WCSIZE > 2 )
		return( ( *wcString > 0xFFFF ) ? FALSE : TRUE );
#endif /* > 16-bit machines */

	/* wchar_t is 16 bits, check whether it's in the form { 00 xx }* or
	   { AA|00 xx }*, either ASCII-as-Unicode or Unicode.  The code used is 
	   safe because to get to this point the string has to be some multiple 
	   of 2 bytes long.  Note that if someone passes in a 1-byte string and 
	   mistakenly includes the terminator in the length it'll be identified 
	   as a 16-bit widechar string, but this doesn't really matter since 
	   it'll get "converted" into a non-widechar string later */
	for( i = 0; i < length; i += WCSIZE )
		{
		const wchar_t wch = *wcString++;

		if( wch > 0xFF )
			{
			const int wchHi = wch >> 8;

			assert( wchHi );

			/* If we haven't already seen a high byte, remember it */
			if( hiByte == 0 )
				hiByte = wchHi;
			else
				/* If the current high byte doesn't match the previous one,
				   it's probably 8-bit chars */
				if( wchHi != hiByte )
					return( FALSE );

			/* Special-case handling for short strings to reduce false
			   positives: If it's a one- or two-wchar_t string and the high 
			   chars are ASCII chars, it's probably ASCII */
			if( length == WCSIZE && wchHi > ' ' )
				return( FALSE );
			if( length == WCSIZE * 2 && i == WCSIZE && \
				hiByte > ' ' && wchHi > ' ' )
				return( FALSE );
			}
		}

	return( TRUE );				/* Probably 16-bit chars */
	}

/* Try and figure out the string type for a string.  This detects (or at 
   least tries to detect) not only the basic string type, but also basic 
   string types encoded as widechar strings, and widechar strings encoded as 
   basic string types */

static ASN1_STRINGTYPE getAsn1StringType( const BYTE *string, int length )
	{
	BOOLEAN notPrintable = FALSE, notIA5 = FALSE;

	assert( string != NULL );
	assert( length > 0 );

	/* If it's a multiple of bmpchar_t in size, check whether it's a 
	   BMPString stuffed into a T61String or an 8-bit string encoded as a 
	   BMPString.  The following code assumes that anything claiming to be a 
	   BMPString is always something else, this currently seems to hold true 
	   for all BMPStrings.  Hopefully by the time anyone gets around to 
	   using > 8-bit characters everyone will be using UTF8Strings because 
	   there's no easy way to distinguish between a byte string which is a 
	   > 8-bit BMPString and a 7/8-bit string */
	if( !( length % UCSIZE ) )
		{
		bmpchar_t *bmpString = ( bmpchar_t * ) string;
		int stringLength = length;

		/* If the first character is a null, it's an 8-bit string stuffed 
		   into a BMPString */
		if( !*string )
			{
			while( stringLength > 0 )
				{
				/* BMPString characters are always big-endian, so we need to 
				   convert them if we're on a little-endian system */
#ifdef DATA_LITTLEENDIAN
				bmpchar_t ch = ( ( *bmpString & 0xFF ) << 8 ) | \
							   ( *bmpString >> 8 );
#else
				bmpchar_t ch = *bmpString;
#endif /* DATA_LITTLEENDIAN */

				/* If the high bit is set, it's not an ASCII subset */
				if( ch >= 128 )
					{
					notPrintable = notIA5 = TRUE;
					if( !asn1CharFlags[ ch & 0x7F ] )
						/* It's not 8859-1 either */
						return( STRINGTYPE_UNICODE );
					}
				else
					/* Check whether it's a PrintableString */
					if( !( asn1CharFlags[ ch ] & P ) )
						notPrintable = TRUE;

				bmpString++;
				stringLength -= UCSIZE;
				}

			return( notIA5 ? STRINGTYPE_UNICODE_T61 : notPrintable ? \
					STRINGTYPE_UNICODE_IA5 : STRINGTYPE_UNICODE_PRINTABLE );
			}
		}

	/* Walk down the string checking each character */
	while( length-- )
		{
		BYTE ch = *string;

		/* If the high bit is set, it's not an ASCII subset */
		if( ch >= 128 )
			{
			notPrintable = notIA5 = TRUE;
			if( !asn1CharFlags[ ch & 0x7F ] )
				/* It's not 8859-1 either, probably some odd widechar type */
				return( STRINGTYPE_NONE );
			}
		else
			{
			/* Check whether it's a PrintableString */
			if( !( asn1CharFlags[ ch ] & P ) )
				notPrintable = TRUE;

			/* Check whether it's something peculiar */
			if( !asn1CharFlags[ ch ] )
				return( STRINGTYPE_NONE );
			}

		string++;
		}

	return( notIA5 ? STRINGTYPE_T61 : notPrintable ? STRINGTYPE_IA5 : \
			STRINGTYPE_PRINTABLE );
	}

static ASN1_STRINGTYPE getNativeStringType( const BYTE *string, int length )
	{
	BOOLEAN notPrintable = FALSE, notIA5 = FALSE;

	assert( string != NULL );
	assert( length > 0 );

	/* If it's a multiple of wchar_t in size, check whether it's a widechar 
	   string.  If it's a widechar string it may actually be something else 
	   that has been bloated out into widechars, so we check for this as 
	   well */
	if( !( length % WCSIZE ) && isNativeWidecharString( string, length ) )
		{
		wchar_t *wcString = ( wchar_t * ) string;

		while( length > 0 )
			{
			wchar_t ch = *wcString;

			/* If the high bit is set, it's not an ASCII subset */
			if( ch >= 128 )
				{
				notPrintable = notIA5 = TRUE;
				if( !nativeCharFlags[ ch & 0x7F ] )
					/* It's not 8859-1 either */
					return( STRINGTYPE_UNICODE );
				}
			else
				/* Check whether it's a PrintableString */
				if( !( nativeCharFlags[ ch ] & P ) )
					notPrintable = TRUE;

			wcString++;
			length -= WCSIZE;
			}

		return( notIA5 ? STRINGTYPE_UNICODE_T61 : notPrintable ? \
				STRINGTYPE_UNICODE_IA5 : STRINGTYPE_UNICODE_PRINTABLE );
		}

	/* Walk down the string checking each character */
	while( length-- )
		{
		BYTE ch = *string;

		/* If the high bit is set, it's not an ASCII subset */
		if( ch >= 128 )
			{
			notPrintable = notIA5 = TRUE;
			if( !nativeCharFlags[ ch & 0x7F ] )
				/* It's not 8859-1 either, probably some odd widechar type */
				return( STRINGTYPE_NONE );
			}
		else
			{
			/* Check whether it's a PrintableString */
			if( !( nativeCharFlags[ ch ] & P ) )
				notPrintable = TRUE;

			/* Check whether it's something peculiar */
			if( !nativeCharFlags[ ch ] )
				return( STRINGTYPE_NONE );
			}

		string++;
		}

	return( notIA5 ? STRINGTYPE_T61 : notPrintable ? STRINGTYPE_IA5 : \
			STRINGTYPE_PRINTABLE );
	}

/* Convert a UTF-8 string to ASCII, 8859-1, or Unicode */

static const int utf8bytesTbl[] = {
	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
	4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6
	};

⌨️ 快捷键说明

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