📄 certstr.c
字号:
#define utf8bytes( value ) ( ( value <= 192 ) ? 1 : \
( value <= 224 ) ? 2 : \
utf8bytesTbl[ ( value ) - 224 ] )
/* Parse one character from the string, enforcing the UTF-8 canonical-
encoding rules:
00 - 7F = 0xxxxxxx
80 - 7FF = 110xxxxx 10xxxxxx
800 - FFFF = 1110xxxx 10xxxxxx 10xxxxxx */
static long getUnicodeChar( const BYTE *stringPtr, const int maxLen,
int *charByteCount )
{
const int firstChar = *stringPtr;
const int count = utf8bytes( firstChar );
long ch;
*charByteCount = count;
if( count < 1 || count > 3 || count > maxLen )
return( CRYPT_ERROR_BADDATA );
switch( count )
{
case 0:
ch = firstChar & 0x7F;
break;
case 1:
if( ( firstChar & 0xE0 ) != 0xC0 || \
( stringPtr[ 1 ] & 0xC0 ) != 0x80 )
return( CRYPT_ERROR_BADDATA );
ch = ( ( firstChar & 0x1F ) << 6 ) | \
( stringPtr[ 1 ] & 0x3F );
break;
case 2:
if( ( firstChar & 0xF0 ) != 0xE0 || \
( stringPtr[ 1 ] & 0xC0 ) != 0x80 || \
( stringPtr[ 2 ] & 0xC0 ) != 0x80 )
return( CRYPT_ERROR_BADDATA );
ch = ( ( firstChar & 0x1F ) << 12 ) | \
( ( stringPtr[ 1 ] & 0x3F ) << 6 ) | \
( stringPtr[ 2 ] & 0x3F );
break;
default:
assert( NOTREACHED );
return( CRYPT_ERROR_BADDATA );
}
return( ch );
}
static int copyFromUtf8String( void *dest, int *destLen, const int maxLen,
const void *source, const int sourceLen )
{
ASN1_STRINGTYPE stringType = STRINGTYPE_PRINTABLE;
const BYTE *srcPtr = source;
wchar_t *wcDestPtr = dest;
BYTE *destPtr = dest;
int noChars = 0, count, i;
/* Clear the return value */
*destLen = 0;
/* Scan the string to determine the widest character type in it */
for( i = 0; i < sourceLen; i += count )
{
const long ch = getUnicodeChar( srcPtr + i, sourceLen - i, &count );
if( ch < 0 || ch > 0xFFFFUL )
return( CRYPT_ERROR_BADDATA );
noChars++;
if( ch > 0xFF )
{
stringType = STRINGTYPE_UNICODE;
break;
}
/* Check which range it fits into */
if( !( asn1CharFlags[ ( 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( asn1CharFlags[ ( int ) ch & 0x7F ] & I )
stringType = STRINGTYPE_T61;
else
{
stringType = STRINGTYPE_UNICODE;
break;
}
}
}
/* Make sure the translated string will fit in the destination buffer */
*destLen = noChars * ( ( stringType == STRINGTYPE_UNICODE ) ? \
WCSIZE : 1 );
if( *destLen > maxLen )
return( CRYPT_ERROR_OVERFLOW );
/* Perform a second pass copying the string over */
for( i = 0; i < sourceLen; i += count )
{
const long ch = getUnicodeChar( srcPtr + i, sourceLen - i, &count );
/* Copy the result as a Unicode or ASCII/8859-1 character */
if( stringType == STRINGTYPE_UNICODE )
*wcDestPtr++ = ( wchar_t ) ch;
else
*destPtr++ = ( BYTE ) ch;
}
return( stringType );
}
/* Check that a text string contains valid characters for its string type.
This is used in non-DN strings where we can't vary the string type based
on the characters being used */
BOOLEAN checkTextStringData( const char *string, const int stringLength,
const BOOLEAN isPrintableString )
{
const int charTypeMask = isPrintableString ? P : I;
int i;
for( i = 0; i < stringLength; i++ )
{
const int ch = string[ i ];
if( ch < 0 || ch >= 128 || !isPrint( ch ) )
return( FALSE );
if( !( nativeCharFlags[ ch ] & charTypeMask ) )
return( FALSE );
}
return( TRUE );
}
/****************************************************************************
* *
* ASN.1 String Conversion Functions *
* *
****************************************************************************/
/* Convert a character string from the format used in the certificate into
the native format. This canonicalises the encoding (e.g. Unicode -> ASCII)
and converts the character set, since we can't read the string with
readCharacterString() because it hasn't been canonicalised at that point */
int copyFromAsn1String( void *dest, int *destLen, const int maxLen,
const void *source, const int sourceLen,
const int stringTag )
{
const ASN1_STRINGTYPE stringType = getAsn1StringType( source, sourceLen );
/* Set default return values */
*destLen = 0;
/* If it's a BMP or UTF-8 string, convert it to the native format */
if( stringType == STRINGTYPE_UNICODE )
{
const bmpchar_t *bmpSrcPtr = ( bmpchar_t * ) source;
wchar_t *wcDestPtr = ( wchar_t * ) dest;
const int newLen = ( sourceLen / UCSIZE ) * WCSIZE;
int i;
if( newLen > maxLen )
return( CRYPT_ERROR_OVERFLOW );
for( i = 0; i < sourceLen / UCSIZE; i++ )
#ifdef DATA_LITTLEENDIAN
/* BMPString characters are always big-endian, so we need to convert
them if we're on a little-endian system */
wcDestPtr[ i ] = ( ( bmpSrcPtr[ i ] & 0xFF ) << 8 ) | \
( bmpSrcPtr[ i ] >> 8 );
#else
wcDestPtr[ i ] = ( wchar_t ) bmpSrcPtr[ i ];
#endif /* DATA_LITTLEENDIAN */
*destLen = newLen;
return( CRYPT_OK );
}
if( stringTag == BER_STRING_UTF8 )
{
return( copyFromUtf8String( dest, destLen, maxLen, source,
sourceLen ) );
}
/* If it's something masquerading as Unicode, convert it to the narrower
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_PRINTABLE || \
stringType == STRINGTYPE_UNICODE_IA5 || \
stringType == STRINGTYPE_UNICODE_T61 )
{
const BYTE *srcPtr = source;
BYTE *destPtr = dest;
int i;
if( sourceLen / UCSIZE > maxLen )
return( CRYPT_ERROR_OVERFLOW );
for( i = 1; i < sourceLen; i += UCSIZE )
*destPtr++ = ( BYTE ) srcPtr[ i ];
*destLen = sourceLen / UCSIZE;
return( CRYPT_OK );
}
/* It's an 8-bit character set, just copy it across */
if( sourceLen > maxLen )
return( CRYPT_ERROR_OVERFLOW );
memcpy( dest, source, sourceLen );
*destLen = sourceLen;
/* If it's a T61String, try and guess whether it's using floating
diacritics and convert them to the correct latin-1 representation.
This is mostly guesswork since some implementations use floating
diacritics and some don't, the only known user is Deutsche Telekom
who use them for a/o/u-umlauts so we only interpret the character if
the result would be one of these values */
if( stringTag == BER_STRING_T61 )
{
BYTE *destPtr = dest;
int length = sourceLen, i;
for( i = 0; i < length - 1; i++ )
if( destPtr[ i ] == 0xC8 )
{
int ch = destPtr[ i + 1 ];
/* If it's an umlautable character, convert the following
ASCII value to the equivalent latin-1 form and move the
rest of the string down */
if( ch == 0x61 || ch == 0x41 || /* a, A */
ch == 0x6F || ch == 0x4F || /* o, O */
ch == 0x75 || ch == 0x55 ) /* u, U */
{
static const struct {
int src, dest;
} charMap[] = {
{ 0x61, 0xE4 }, { 0x41, 0xC4 }, /* a, A */
{ 0x6F, 0xF6 }, { 0x4F, 0xD6 }, /* o, O */
{ 0x75, 0xFC }, { 0x55, 0xDC }, /* u, U */
{ 0x00, '?' }
};
int charIndex;
for( charIndex = 0; charMap[ charIndex ].src && \
charMap[ charIndex ].src != ch; charIndex++ );
destPtr[ i ] = charMap[ charIndex ].dest;
if( length - i > 2 )
memmove( destPtr + i + 1, destPtr + i + 2,
length - ( i + 2 ) );
length--;
}
}
*destLen = length;
}
return( CRYPT_OK );
}
/* Convert a character string from the native format to the format used in
the certificate. This canonicalises the encoding (e.g. Unicode -> ASCII)
but doesn't convert the character set, since this is done by
writeCharacterString() */
int copyToAsn1String( void *dest, int *destLen, const int maxLen,
const void *source, const int sourceLen )
{
const ASN1_STRINGTYPE stringType = getNativeStringType( source, sourceLen );
/* If it's Unicode, convert it to the appropriate format */
if( stringType == STRINGTYPE_UNICODE )
{
const wchar_t *srcPtr = ( wchar_t * ) source;
bmpchar_t *bmpDestPtr = ( bmpchar_t * ) dest;
const int newLen = ( sourceLen / WCSIZE ) * UCSIZE;
int length = sourceLen, i;
/* If it's just a length check, we're done */
*destLen = newLen;
if( newLen > maxLen )
return( CRYPT_ERROR_OVERFLOW );
if( dest == NULL )
return( BER_STRING_BMP );
/* Copy the string across, converting from wchar_t to bmpchar_t as
we go, with endianness conversion if necessary */
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;
}
return( BER_STRING_BMP );
}
/* If it's something masquerading as Unicode, convert it to the narrower
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_PRINTABLE || \
stringType == STRINGTYPE_UNICODE_IA5 || \
stringType == STRINGTYPE_UNICODE_T61 )
{
*destLen = sourceLen / WCSIZE;
if( sourceLen / WCSIZE > maxLen )
return( CRYPT_ERROR_OVERFLOW );
if( dest != NULL )
{
const wchar_t *srcPtr = ( wchar_t * ) source;
BYTE *destPtr = dest;
int i;
for( i = 0; i < sourceLen; i += WCSIZE )
*destPtr++ = ( BYTE ) *srcPtr++;
}
return( ( stringType == STRINGTYPE_UNICODE_PRINTABLE ) ? \
BER_STRING_PRINTABLE : \
( stringType == STRINGTYPE_UNICODE_IA5 ) ? \
BER_STRING_IA5 : BER_STRING_T61 );
}
/* It's an 8-bit character set, just copy it across */
*destLen = sourceLen;
if( sourceLen > maxLen )
return( CRYPT_ERROR_OVERFLOW );
if( dest != NULL )
memcpy( dest, source, sourceLen );
return( ( stringType == STRINGTYPE_PRINTABLE ) ? \
BER_STRING_PRINTABLE : \
( stringType == STRINGTYPE_IA5 ) ? \
BER_STRING_IA5 : BER_STRING_T61 );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -