📄 dnstring.c
字号:
( string[ 1 ] & 0xC0 ) != 0x80 || \
( string[ 2 ] & 0xC0 ) != 0x80 )
return( CRYPT_ERROR_BADDATA );
ch = ( ( firstChar & 0x1F ) << 12 ) | \
( ( string[ 1 ] & 0x3F ) << 6 ) | \
( string[ 2 ] & 0x3F );
break;
default:
assert( NOTREACHED );
return( CRYPT_ERROR_BADDATA );
}
return( ch );
}
#if 0 /* Currently unused, see note at start */
static int putUTF8Char( BYTE *string, const long ch )
{
if( ch < 0x80 )
{
*string = ( BYTE ) ch;
return( 1 );
}
if( ch < 0x0800 )
{
*string++ = ( BYTE )( 0xC0 | ch >> 6 );
*string = ( BYTE )( 0x80 | ch & 0x3F );
return( 2 );
}
*string++ = ( BYTE )( 0xE0 | ch >> 12 );
*string++ = ( BYTE )( 0x80 | ( ( ch >> 6 ) & 0x3F ) );
*string = ( BYTE )( 0x80 | ch & 0x3F );
return( 3 );
}
#endif /* 0 */
/* Determine the length of a string encoded as UTF-8 */
static int utf8DestStringLen( const void *string, const int stringLen,
const BOOLEAN isWideChar )
{
if( isWideChar )
{
const wchar_t *wcStrPtr = ( wchar_t * ) string;
int length = 0, i;
for( i = 0; i < stringLen; i += WCSIZE )
{
const wchar_t ch = *wcStrPtr++;
length += ( ch < 0x80 ) ? 1 : ( ch < 0x0800 ) ? 2 : 3;
}
return( length );
}
return( stringLen );
}
/* Convert a UTF-8 string to ASCII, 8859-1, or Unicode, and vice versa */
static int copyFromUtf8String( void *dest, int *destLen, const int destMaxLen,
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;
assert( isWritePtr( dest, destMaxLen ) );
assert( isWritePtr( destLen, sizeof( int ) ) );
assert( isReadPtr( source, sourceLen ) );
/* Clear the return value */
*destLen = 0;
/* Scan the string to determine its length and the widest character type
in it. We have to process the entire string even once we've
identified it as containing the widest string type (Unicode) in order
to check for malformed chars */
for( i = 0; i < sourceLen; i += count )
{
const long ch = getUTF8Char( srcPtr + i, sourceLen - i, &count );
if( ch < 0 || ch > 0xFFFFL )
return( CRYPT_ERROR_BADDATA );
noChars++;
if( stringType == STRINGTYPE_UNICODE || ch > 0xFF )
stringType = STRINGTYPE_UNICODE;
else
/* If it's not a PrintableString char, mark it as T61 if it's
within range, otherwise it's Unicode */
if( ch >= 128 )
stringType = ( asn1CharFlags[ ( int ) ch & 0x7F ] & P ) ? \
STRINGTYPE_T61 : STRINGTYPE_UNICODE;
}
/* Make sure that the translated string will fit into the destination
buffer */
*destLen = noChars * ( ( stringType == STRINGTYPE_UNICODE ) ? \
WCSIZE : 1 );
if( *destLen > destMaxLen )
return( CRYPT_ERROR_OVERFLOW );
/* Perform a second pass copying the string over */
for( i = 0; i < sourceLen; i += count )
{
const long ch = getUTF8Char( 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 );
}
#if 0 /* Currently unused, see note at start */
static int copyToUtf8String( void *dest, const int destMaxLen,
const void *source, const int sourceLen,
const BOOLEAN isWideChar )
{
assert( isWritePtr( dest, destMaxLen ) );
assert( isReadPtr( source, sourceLen ) );
if( isWideChar )
{
const wchar_t *wcStrPtr = source;
BYTE *destPtr = dest;
int length = 0, i;
for( i = 0; i < sourceLen; i += WCSIZE )
{
length += putUTF8Char( destPtr, *wcStrPtr++ );
destPtr += length;
}
return( length );
}
memcpy( dest, source, sourceLen );
return( sourceLen );
}
#endif /* 0 */
/****************************************************************************
* *
* ASN.1 String Conversion Functions *
* *
****************************************************************************/
/* 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 );
}
/* Convert a character string from the format used in the certificate into
the native format */
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,
stringTag );
assert( isWritePtr( dest, maxLen ) );
assert( isWritePtr( destLen, sizeof( int ) ) );
assert( isReadPtr( source, sourceLen ) );
/* Clear return values */
*destLen = 0;
/* If it's a BMP or UTF-8 string, convert it to the native format */
if( stringType == STRINGTYPE_UNICODE )
{
const BYTE *string = source;
wchar_t *wcDestPtr = ( wchar_t * ) dest;
const int newLen = ( sourceLen / UCSIZE ) * WCSIZE;
int i;
assert( !( ( int ) dest & 1 ) );
if( newLen > maxLen )
return( CRYPT_ERROR_OVERFLOW );
/* Since we're reading bmpchar_t-sized values from a char-aligned
source, we have to assemble the data a byte at a time to handle
systems where non-char values can only be accessed on word-
aligned boundaries */
for( i = 0; i < sourceLen / UCSIZE; i++ )
{
*wcDestPtr++ = getBmpchar( string );
string += UCSIZE;
}
*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 separately */
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 */
int getAsn1StringInfo( const void *string, const int stringLen,
int *stringType, int *asn1StringType,
int *asn1StringLen )
{
assert( isReadPtr( string, stringLen ) );
assert( isWritePtr( stringType, sizeof( int ) ) );
assert( isWritePtr( asn1StringType, sizeof( int ) ) );
assert( isWritePtr( asn1StringLen, sizeof( int ) ) );
*stringType = getNativeStringType( string, stringLen );
switch( *stringType )
{
case STRINGTYPE_UNICODE:
/* It's a widechar string, output is Unicode */
*asn1StringLen = ( stringLen / WCSIZE ) * UCSIZE;
*asn1StringType = BER_STRING_BMP;
return( CRYPT_OK );
case STRINGTYPE_UNICODE_PRINTABLE:
case STRINGTYPE_UNICODE_IA5:
case STRINGTYPE_UNICODE_T61:
/* It's an ASCII string masquerading as Unicode, output is an
8-bit string type */
*asn1StringLen = stringLen / WCSIZE;
*asn1StringType = ( *stringType == STRINGTYPE_UNICODE_PRINTABLE ) ? \
BER_STRING_PRINTABLE : \
( *stringType == STRINGTYPE_UNICODE_IA5 ) ? \
BER_STRING_IA5 : BER_STRING_T61;
return( CRYPT_OK );
case STRINGTYPE_UTF8:
/* It's a widechar string encoded as UTF-8, output is a
variable-length UTF-8 string. This isn't currently used
but is only present as a placeholder, see the comment at the
start of this module for details */
*asn1StringLen = utf8DestStringLen( string, stringLen,
( *stringType == STRINGTYPE_UNICODE || \
*stringType == STRINGTYPE_UNICODE_PRINTABLE || \
*stringType == STRINGTYPE_UNICODE_IA5 || \
*stringType == STRINGTYPE_UNICODE_T61 ) ? \
TRUE : FALSE );
*asn1StringType = BER_STRING_UTF8;
return( CRYPT_OK );
default:
/* It's an ASCII string */
*asn1StringLen = stringLen;
*asn1StringType = ( *stringType == STRINGTYPE_PRINTABLE ) ? \
BER_STRING_PRINTABLE : \
( *stringType == STRINGTYPE_IA5 ) ? \
BER_STRING_IA5 : BER_STRING_T61;
return( CRYPT_OK );
}
assert( NOTREACHED );
return( CRYPT_ERROR ); /* Get rid of compiler warning */
}
int copyToAsn1String( void *dest, int *destLen, const int maxLen,
const void *source, const int sourceLen,
const int stringType )
{
assert( isWritePtr( dest, maxLen ) );
assert( isWritePtr( destLen, sizeof( int ) ) );
assert( isReadPtr( source, sourceLen ) );
switch( stringType )
{
case STRINGTYPE_UNICODE:
{
const BYTE *srcPtr = source;
BYTE *destPtr = dest;
const int newLen = ( sourceLen / WCSIZE ) * UCSIZE;
int length = sourceLen, i;
/* It's a widechar, convert it to Unicode */
*destLen = newLen;
if( newLen > maxLen )
return( CRYPT_ERROR_OVERFLOW );
/* 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 )
{
const wchar_t wCh = getWidechar( srcPtr );
srcPtr += WCSIZE;
*destPtr++ = ( BYTE ) ( ( wCh >> 8 ) & 0xFF );
*destPtr++ = ( BYTE ) ( wCh & 0xFF );
}
return( CRYPT_OK );
}
case STRINGTYPE_UNICODE_PRINTABLE:
case STRINGTYPE_UNICODE_IA5:
case STRINGTYPE_UNICODE_T61:
{
const wchar_t *srcPtr = ( wchar_t * ) source;
BYTE *destPtr = dest;
int i;
/* 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 separately */
*destLen = sourceLen / WCSIZE;
if( sourceLen / WCSIZE > maxLen )
return( CRYPT_ERROR_OVERFLOW );
for( i = 0; i < sourceLen; i += WCSIZE )
*destPtr++ = ( BYTE ) *srcPtr++;
return( CRYPT_OK );
}
default:
/* It's an 8-bit character set, just copy it across */
*destLen = sourceLen;
if( sourceLen > maxLen )
return( CRYPT_ERROR_OVERFLOW );
memcpy( dest, source, sourceLen );
return( CRYPT_OK );
}
assert( NOTREACHED );
return( CRYPT_ERROR ); /* Get rid of compiler warning */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -