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

📄 certstr.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 5 页
字号:
/****************************************************************************
*																			*
*						 Certificate String/DN Routines						*
*						Copyright Peter Gutmann 1996-2002					*
*																			*
****************************************************************************/

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

/* DN component info flags.  Some implementations may place more than one
   AVA into a RDN.  In this case we set a flag to indicate that the RDN
   continues in the next DN component structure.  If the RDN/DN was set by
   specifying the entire DN at once using a text DN string, it's not a good
   idea to allow random changes to it so we mark the components as locked.
   If we're reading data from an external source the DN can contain all sorts
   of strange stuff, so we set a flag to tell the DN component-handling code
   not to perform any validity checking on the components as they're added */

#define DN_FLAG_CONTINUED	0x01	/* RDN continues with another AVA */
#define DN_FLAG_LOCKED		0x02	/* RDN can't be modified */
#define DN_FLAG_NOCHECK		0x04	/* Don't check validity of components */

/* The structure to hold a DN component */

typedef struct DC {
	/* The next and previous list element in the linked list of DN
	   components */
	struct DC *next, *prev;

	/* DN component type and type information */
	CRYPT_ATTRIBUTE_TYPE type;		/* cryptlib component type */
	ASN1_STRINGTYPE stringType;		/* Component string data type */
	const void *typeInfo;			/* Type info for this component */

	/* Various flags for this RDN or AVA: Whether the RDN continues with
	   another AVA, whether the RDN is locked against modification */
	int flags;

	/* DN component data.  If it's a sensible-length value (virtually all
	   are) we use a fixed memory block for the value data because it's not
	   worth the overhead of mallocing each tiny block, if it's a longer
	   string we store it in a dynamically-allocated buffer */
	BYTE smallValue[ CRYPT_MAX_TEXTSIZE ];
	void *value;					/* Attribute data payload */
	int valueLength;				/* The value of this component */

	/* Encoding information: The overall size of the RDN data (without the
	   tag and length) if this is the first or only component of an RDN, and
	   the size of the AVA data */
	int encodedRDNdataSize, encodedAVAdataSize;
	} DN_COMPONENT;

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

/* Most systems now include some sort of support for various wide char
   functions.  We require wchar_t (not supported older DOS compilers and
   legacy Unixen), mbstowcs() (usually supported, but with varying degrees of
   success), and towlower() (everything from unsupported to token support to
   relatively good support).  In addition since wchar_t can be anything from
   8 bits (Borland C++ under DOS) to 64 bits (RISC Unixen), we define a
   bmpchar_t (short for Unicode/BMPString char) which is always 16 bits as
   required for BMPStrings.  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 */
#if defined( __MSDOS16__ ) && !defined( __BORLANDC__ )
  typedef unsigned short int wchar_t;		/* Widechar data type */
#endif /* OS's which don't support wide chars */
#if defined( __BORLANDC__ ) && ( __BORLANDC__ == 0x410 )
  #define wchar_t unsigned short int	/* BC++ 3.1 has an 8-bit wchar_t */
#endif /* BC++ 3.1 */
#ifdef __UNIX__
  #if defined( __hpux ) || defined( _AIX ) || defined( _M_XENIX )
	#include <wchar.h>
	#define HAS_TOWLOWER
  /* The following check tries to include the wcXXX stuff by default,
     which should work for most recent Unixen */
  #elif !( defined( __linux__ ) || ( defined( sun ) && OSVERSION < 5 ) || \
		   defined( __bsdi__ ) || defined( __FreeBSD__ ) || \
		   defined( __OpenBSD__ ) || defined( __SCO_VERSION__ ) )
	#include <wctype.h>
	#define HAS_TOWLOWER
  #endif /* OS's which support towlower() */
#endif /* __UNIX__ */
#if defined( __WIN32__ ) && \
	!( defined( __BORLANDC__ ) && ( __BORLANDC__ < 0x500 ) )
  /* Win95 doesn't have Unicode support so we can't use CompareString()
	 since it compares ANSI rather than Unicode strings.  However there is
	 support for towlower() via the C library, so we can use the general
	 wchar_t comparison routines */
  #include <wchar.h>
  #define HAS_TOWLOWER
#endif /* __WIN32__ */
#ifdef __IBM4758__
  /* Embedded environments rarely have i18n support */
  #define NO_WIDECHAR
#endif /* __IBM4758__ */

/* The CSTR_EQUAL define doesn't appear unless the October'97 MSDN stealth
   upgrade is installed, so we define it here if it's not already defined */

#if defined( __WIN32__ ) && !defined( CSTR_EQUAL )
  #define CSTR_EQUAL	2
#endif /* __WIN32__ && !CSTR_EQUAL */

/* Useful defines to help with scaling offsets and lengths for wchar_t and
   bmpchar_t strings */

#define WCSIZE	( sizeof( wchar_t ) )
#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 int charFlags[] = {
	/* 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
	};

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

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

	/* Check for a Unicode BOM at the start of the string */
	if( *wcString == 0xFFFE || *wcString == 0xFEFF )
		return( TRUE );		/* Definitely Unicode with a BOM */

#if !defined( __MSDOS16__ ) && !defined( __WIN16__ )
	/* 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( WCSIZE > 2 )
		return( ( *wcString > 0x0FFFF ) ? FALSE : TRUE );
#endif /* > 16-bit machines */

	/* wchar_t is 16 bits, check whether it's in the form 00 xx 00 xx.  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 += 2 )
		{
		if( *wcString > 0xFF )
			return( FALSE );	/* Probably 8-bit chars */
		wcString++;
		}

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

/* Try and figure out the ASN.1 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 BMPStrings encoded as basic
   string types */

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

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

	/* Try and figure out whether it's a widechar or BMPString.  In theory
	   under NT we could insert:

		#ifdef __WIN32__
			if( !isWin95 && IsTextUnicode( ( CONST LPVOID ) string, length, NULL ) )
				return( STRINGTYPE_UNICODE );
			else
		#endif

	   before the following code, however the tests in IsTextUnicode() seem
	   to be pretty simplistic and aren't very reliable (for example they
	   won't report a latin1 string encoded as Unicode as being Unicode).
	   Because of this we don't even try to use it and instead use our own
	   tests on all platforms.  These use all sorts of ad-hockery to try and
	   guess whether a string is a widechar/BMPString one or not.  This
	   usually works, but probably mainly because we rarely encounter
	   widechar/BMPString strings */
	if( !isASN1string )
		{
		/* If it a multiple of wchar_t or bmpchar_t in size, check whether it's
		   a widechar string.  If it's a widechar string it may actually be
		   something else which has been bloated out into widechars, so we
		   check for this as well */
		if( !( length % WCSIZE ) && isWidecharString( string, length ) )
			{
			wchar_t *wcString = ( wchar_t * ) string;

			/* Make sure we don't include the BOM in the test */
			if( *wcString == 0xFFFE || *wcString == 0xFEFF )
				{ wcString++; length -= WCSIZE; }

			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( !charFlags[ ch & 0x7F ] )
						/* It's not 8859-1 either */
						return( STRINGTYPE_UNICODE );
					}
				else
					/* Check whether it's a PrintableString */
					if( !( charFlags[ ch ] & P ) )
						notPrintable = TRUE;

				wcString++;
				length -= WCSIZE;
				}

			return( notIA5 ? STRINGTYPE_UNICODE_T61 : notPrintable ? \
					STRINGTYPE_UNICODE_IA5 : STRINGTYPE_UNICODE_PRINTABLE );
			}
		}
	else
		/* 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
		   UTF8String's 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( !charFlags[ ch & 0x7F ] )
							/* It's not 8859-1 either */
							return( STRINGTYPE_UNICODE );
						}
					else
						/* Check whether it's a PrintableString */
						if( !( charFlags[ 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( !charFlags[ ch & 0x7F ] )
				/* It's not 8859-1 either, probably some odd widechar type */
				return( STRINGTYPE_NONE );
			}
		else
			{
			/* Check whether it's a PrintableString */
			if( !( charFlags[ ch ] & P ) )
				notPrintable = TRUE;

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

		string++;
		}

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

/* The SET string type is much more sensible, we map the ASN.1 string types
   to the subset used by SET */

static ASN1_STRINGTYPE getSETStringType( const BYTE *string, const int length,
										 const BOOLEAN isASN1string )
	{
	ASN1_STRINGTYPE type = getStringType( string, length, isASN1string );

	/* If it can be translated directly to a SETString type, use that */
	if( type == STRINGTYPE_IA5 || type == STRINGTYPE_PRINTABLE )
		return( STRINGTYPE_VISIBLE );
	if( type == STRINGTYPE_UNICODE || type == STRINGTYPE_UNICODE_T61 )
		return( STRINGTYPE_UNICODE );
	if( type == STRINGTYPE_UNICODE_IA5 || type == STRINGTYPE_UNICODE_PRINTABLE )
		return( STRINGTYPE_UNICODE_VISIBLE );

⌨️ 快捷键说明

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