📄 certstr.c
字号:
/* It can't be directly translated, we need to convert it to Unicode */
return( STRINGTYPE_T61_UNICODE );
}
/* Convert a character string into a format in which it can be used in a
certificate. This copies the string across unchanged if it'll fit into
the allowed 8-bit string type, or converts it to Unicode if it won't (see
the "X.509 Style Guide" for the rationale behind this). The Unicode
conversion is rather OS-dependant, under Windows NT we can Do It Right,
under environments which support mbstowc() we can Do It As Right As The
Implementation Gets It, but in other environments we just assume ISO
8859-1 and do a brute-force conversion (this is actually equivalent to
what a lot of mbstowc() implementations do) */
static ASN1_STRINGTYPE copyConvertString( const void *source, const int sourceLen,
void *dest, int *destLen,
const int maxLen,
const BOOLEAN isSETString,
const BOOLEAN isASN1string )
{
ASN1_STRINGTYPE stringType;
/* Set default return values */
*destLen = 0;
/* Determine the string type */
if( isSETString )
stringType = getSETStringType( source, sourceLen, isASN1string );
else
stringType = getStringType( source, sourceLen, isASN1string );
/* If it's Unicode or something masquerading as Unicode, convert it to
the appropriate format. Note that STRINGTYPE_UNICODE_VISIBLE is
already covered by STRINGTYPE_UNICODE_IA5, so we don't need to check
for this seperately */
if( stringType == STRINGTYPE_UNICODE || \
stringType == STRINGTYPE_UNICODE_PRINTABLE || \
stringType == STRINGTYPE_UNICODE_IA5 || \
stringType == STRINGTYPE_UNICODE_T61 )
{
wchar_t *srcPtr = ( wchar_t * ) source;
int length = sourceLen;
BYTE *destPtr;
/* If it's from an ASN.1 source (ie it's a BMPString) and contains
an intrinsically narrower character type, copy it across to the
narrower string type */
if( isASN1string && stringType != STRINGTYPE_UNICODE )
{
bmpchar_t *bmpSrcPtr = ( bmpchar_t * ) source;
int i;
if( length / UCSIZE > maxLen )
return( STRINGTYPE_NONE );
destPtr = dest;
for( i = 0; i < length; i += UCSIZE )
{
#ifdef DATA_LITTLEENDIAN
*destPtr++ = ( BYTE ) ( *bmpSrcPtr++ >> 8 );
#else
*destPtr++ = *bmpSrcPtr++;
#endif /* DATA_LITTLEENDIAN */
}
*destLen = length / UCSIZE;
/* Return the converted string type */
return( stringType - 1 );
}
/* If the first character is a BOM, skip it */
if( *srcPtr == 0xFFFE || *srcPtr == 0xFEFF )
{
srcPtr++;
length -= WCSIZE;
}
/* If it's a pure Unicode string, copy it across, converting from
wchar_t to bmpchar_t as we go. Since the internal/encoded form of
a Unicode string is a BMPString, if we're running on a little-
endian system we also convert it to big-endian */
if( stringType == STRINGTYPE_UNICODE )
{
bmpchar_t *bmpDestPtr = ( bmpchar_t * ) dest;
int newSize = ( length / WCSIZE ) * UCSIZE, i;
if( newSize > maxLen )
return( STRINGTYPE_NONE );
for( i = 0; i < length; i += WCSIZE )
{
wchar_t ch = *srcPtr++;
#ifdef DATA_LITTLEENDIAN
ch = ( ( ch & 0xFF ) << 8 ) | ( ch >> 8 );
#endif /* DATA_LITTLEENDIAN */
*bmpDestPtr++ = ch;
}
*destLen = newSize;
return( STRINGTYPE_UNICODE );
}
/* It's some 8-bit string type masquerading as a Unicode string,
convert the characters to the 8-bit string type */
if( ( int ) ( length / WCSIZE ) > maxLen )
return( STRINGTYPE_NONE );
destPtr = dest;
while( *srcPtr )
*destPtr++ = ( BYTE ) *srcPtr++;
*destLen = length / WCSIZE;
/* Return the converted string type */
return( stringType - 1 );
}
/* If it's a non-Unicode string which needs to be recoded as Unicode,
convert it to Unicode */
if( stringType == STRINGTYPE_T61_UNICODE )
{
#ifdef DATA_LITTLEENDIAN
bmpchar_t *bmpStrPtr;
int destChars, i;
#endif /* DATA_LITTLEENDIAN */
if( sourceLen * UCSIZE > maxLen )
return( STRINGTYPE_NONE );
#ifdef __WIN32__
/* It's some non-Unicode string, convert it to Unicode */
*destLen = MultiByteToWideChar( GetACP(), 0, source, -1, dest,
sourceLen ) * UCSIZE;
#else
#ifndef NO_WIDECHAR
#if defined( __MSDOS16__ ) || defined( __WIN16__ )
/* If the widechar set is Unicode, convert it directly */
*destLen = mbstowcs( dest, source, sourceLen ) * UCSIZE;
#else
if( WCSIZE == UCSIZE )
/* If the widechar set is Unicode, convert it directly */
*destLen = mbstowcs( dest, source, sourceLen ) * UCSIZE;
else
{
/* It's a character set in the native word size, convert it up to
this and then back down to a BMPString */
wchar_t wcTemp[ CRYPT_MAX_TEXTSIZE + 1 ], *wcTmpPtr = wcTemp;
bmpchar_t *bmpDestPtr = dest;
int length, i;
length = mbstowcs( wcTemp, source, sourceLen );
for( i = 0; i < length; i++ )
*bmpDestPtr++ = ( bmpchar_t ) *wcTmpPtr++;
*destLen = length * WCSIZE;
}
#endif /* 16-bit machines */
#else
{
/* No wide char support, do a brute-force conversion of 8-bit char to
BMPString */
BYTE *sourcePtr = ( BYTE * ) source;
bmpchar_t *bmpDestPtr = dest;
while( *sourcePtr )
*bmpDestPtr++ = *sourcePtr++;
*destLen = sourceLen * UCSIZE; /* Unicode = RAM vendor conspiracy */
}
#endif /* NO_WIDECHAR */
#endif /* OS-specific Unicode processing */
#ifdef DATA_LITTLEENDIAN
/* BMPString characters are always big-endian, so we need to convert
them if the string was generated on a little-endian system */
bmpStrPtr = dest;
destChars = *destLen / UCSIZE;
for( i = 0; i < destChars; i++ )
bmpStrPtr[ i ] = ( ( bmpStrPtr[ i ] & 0xFF ) << 8 ) | \
( bmpStrPtr[ i ] >> 8 );
#endif /* DATA_LITTLEENDIAN */
/* Now it's a BMPString */
return( STRINGTYPE_UNICODE );
}
/* It's not Unicode, just copy it across */
if( sourceLen > maxLen )
return( STRINGTYPE_NONE );
memcpy( dest, source, sourceLen );
*destLen = sourceLen;
return( stringType );
}
/* 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
};
#define utf8bytes( value ) ( ( value <= 192 ) ? 1 : \
( value <= 224 ) ? 2 : \
utf8bytesTbl[ ( value ) - 224 ] )
ASN1_STRINGTYPE convertFromUTF8( BYTE *destPtr, int *destLen,
const BYTE *srcPtr, const int srcLen )
{
static const LONG offsetFromUTF8[] = {
0x00000000UL, 0x00003080UL, 0x000E2080UL,
0x03C82080UL, 0xFA082080UL, 0x82082080UL
};
ASN1_STRINGTYPE stringType = STRINGTYPE_PRINTABLE;
int i = 0;
/* Clear the return value */
*destLen = 0;
/* Scan the string to determine the widest character type in it */
while( i < srcLen )
{
LONG ch = 0;
int count = utf8bytes( *srcPtr ), j;
/* Parse one character from the string */
i += count;
if( i > srcLen )
return( STRINGTYPE_NONE );
for( j = 0; j < count; j++ )
{
ch <<= 6;
ch += *srcPtr++;
}
ch -= offsetFromUTF8[ count - 1 ];
/* Check which range it fits into */
if( !( charFlags[ ( int ) ch ] & P ) )
{
/* If it's not a PrintableString char, mark it as T61 if it's
within range and we haven't already hit a Unicode char */
if( ch < 0xFF && ( charFlags[ ( int ) ch & 0x7F ] & I ) && \
stringType != STRINGTYPE_UNICODE )
stringType = STRINGTYPE_T61;
else
stringType = STRINGTYPE_UNICODE;
}
}
/* Perform a second pass copying the string over */
i = 0;
while( i < srcLen )
{
LONG ch = 0;
int count = utf8bytes( *srcPtr ), j;
/* Parse one character from the string */
i += count;
if( i > srcLen )
return( STRINGTYPE_NONE );
for( j = 0; j < count; j++ )
{
ch <<= 6;
ch += *srcPtr++;
}
ch -= offsetFromUTF8[ count - 1 ];
/* If the result won't fit into a Unicode character, replace it with
a kanitvustan */
if( ch > 0xFFFF )
ch = 0xFFFD;
/* Copy the result as a Unicode or ASCII/8859-1 character */
if( stringType == STRINGTYPE_UNICODE )
{
*destPtr++ = ( BYTE ) ( ch >> 8 );
( *destLen )++;
}
*destPtr++ = ( BYTE ) ch;
( *destLen )++;
}
return( stringType );
}
/* Strip leading, trailing, and repeated internal spaces from an ASN.1
string. This gets somewhat complicated because there are many ways of
encoding a space. The best we can do is to assume that either 0x20 or
0xA0 are spaces */
#ifdef DATA_BIGENDIAN
#define ASCII_SPC 0x0020
#define ASCII_NBS 0x00A0
#else
#define ASCII_SPC 0x2000
#define ASCII_NBS 0xA000
#endif /* Endianness-dependant ASCII-in-Unicode values */
static int stripASN1spaces( void **string, int length, BOOLEAN isUnicode )
{
BYTE *strptr = *string;
int i = 2;
if( isUnicode )
{
bmpchar_t *bmpStrptr = *string;
/* Convert the length value from bytes to Unicode characters */
length /= UCSIZE;
/* Strip leading and trailing spaces */
while( length && ( *bmpStrptr == ASCII_SPC || *bmpStrptr == ASCII_NBS ) )
{ bmpStrptr++; length --; }
while( length && ( bmpStrptr[ length - 1 ] == ASCII_SPC || \
bmpStrptr[ length - 1 ] == ASCII_NBS ) )
length--;
/* Strip internal spaces */
while( i <= length - 2 )
{
if( ( bmpStrptr[ i - 1 ] == ASCII_SPC || bmpStrptr[ i - 1 ] == ASCII_NBS ) && \
( bmpStrptr[ i ] == ASCII_SPC || bmpStrptr[ i ] == ASCII_NBS ) )
{
memmove( bmpStrptr + i, bmpStrptr + i + 1, \
( length - ( i + 1 ) ) * UCSIZE );
length--;
}
else
i++;
}
return( length * UCSIZE );
}
/* Strip leading and trailing spaces */
while( length && ( *strptr == 0x20 || *strptr == 0xA0 ) )
{ strptr++; length--; }
while( length && ( strptr[ length - 1 ] == 0x20 || \
strptr[ length - 1 ] == 0xA0 ) )
length--;
/* Strip internal spaces */
while( i <= length - 2 )
{
if( ( strptr[ i - 1 ] == 0x20 || strptr[ i - 1 ] == 0xA0 ) && \
( strptr[ i ] == 0x20 || strptr[ i ] == 0xA0 ) )
{
memmove( strptr + i, strptr + i + 1, length - ( i + 1 ) );
length--;
}
else
i++;
}
return( length );
}
/* Compare two ASN.1 strings in a case-insensitive manner. This is only
guaranteed to work for straight ASCII strings, for everything else it
ranges from pure guesswork (most systems) to bare bones support (8859-1
only under Solaris, PHUX, AIX) to vague support (Unicode under Win95,
OSF/1) to reasonable support (Windows NT) */
BOOLEAN compareASN1string( const void *string1, const int string1len,
const void *string2, const int string2len )
{
BYTE str1[ ( CRYPT_MAX_TEXTSIZE + 1 ) * 2 ], *str1ptr = str1;
BYTE str2[ ( CRYPT_MAX_TEXTSIZE + 1 ) * 2 ], *str2ptr = str2;
BOOLEAN str1unicode = FALSE, str2unicode = FALSE;
int str1len, str2len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -