📄 certstr.c
字号:
#if defined( __BORLANDC__ ) && ( __BORLANDC__ == 0x410 )
/* Borland C++ 3.1 has an 8-bit wchar_t which causes problems with the
conversion code above which assumes wchar_t is at least as wide as a
BMPString char, so we set the whole array to zero before converting
the string which means any extraneous positions will have identical
values */
memset( str1, 0, ( ( CRYPT_MAX_TEXTSIZE + 1 ) * 2 ) );
memset( str2, 0, ( ( CRYPT_MAX_TEXTSIZE + 1 ) * 2 ) );
#endif /* BC++ 3.1 */
/* First we convert the strings into canonical form, either ASCII or
Unicode. We can't rely on the encoded type because some
implementations will stuff almost anything (including Unicode) into a
T61String, so we try and guess the exact type ourselves and then
convert it to a type we can work with. By forcing a conversion to a
SETString we end up with either ASCII or Unicode */
if( copyConvertString( string1, string1len, str1, &str1len,
CRYPT_MAX_TEXTSIZE, TRUE, TRUE ) == STRINGTYPE_UNICODE )
str1unicode = TRUE;
if( copyConvertString( string2, string2len, str2, &str2len,
CRYPT_MAX_TEXTSIZE, TRUE, TRUE ) == STRINGTYPE_UNICODE )
str2unicode = TRUE;
/* If one can only be represented in Unicode and the other is fine as
ASCII, they're definitely different. After this test, they're either
both ASCII or both Unicode */
if( ( str1unicode && !str2unicode ) || ( !str1unicode && str2unicode ) )
return( FALSE );
/* Now we have to strip leading, trailing, and internal spaces. This
gets somewhat complicated because there are many ways of encoding a
space. If the stripped strings differ in length after they've been
stripped, they're different */
str1len = stripASN1spaces( ( void ** ) &str1ptr, str1len, str1unicode );
str2len = stripASN1spaces( ( void ** ) &str2ptr, str2len, str2unicode );
if( str1len != str2len )
return( FALSE );
#ifdef __WIN32__
/* Compare the string using the Win32 native string compare function.
Under NT this compares Unicode strings, under Win95 it only compares
ANSI strings so we can only use it under NT. When making the
comparison, we ignore the string case, there are other options as
well but these probably aren't useful */
if( !isWin95 )
return( ( CompareString( LOCALE_USER_DEFAULT, NORM_IGNORECASE, str1ptr,
str1len / UCSIZE, str2ptr, str2len / UCSIZE ) == CSTR_EQUAL ) ? \
TRUE : FALSE );
#endif /* __WIN32__ */
/* If it's a Unicode string, we try to perform the comparison in a case-
insensitive manner. This is almost impossible to do, the few systems
which support towlower() only include fairly patchy support for the
full Unicode character range (many only support 8859-1), or handle
things in a locale-specific manner (for example if the current locale
supports the given Unicode characters, the conversion works, otherwise
the character is returned unchanged) */
if( str1unicode )
{
while( str1len )
{
wchar_t ch1, ch2;
/* Extract the next two characters from the string */
ch1 = mgetBWord( str1ptr );
ch2 = mgetBWord( str2ptr );
#ifdef HAS_TOWLOWER
if( towlower( ch1 ) != towlower( ch2 ) )
break;
#else
/* If there's no support for towlower(), the best we can do is
try to convert single-octet characters as if they were ASCII/
8859-1, and compare the rest unchanged. Note that we go for
the full 8-bit range in tolower() for the systems which do
support 8859-1 for this function, the worst that can happen is
that the value will be returned unchanged */
if( ch1 <= 0xFF && ch2 <= 0xFF )
{
if( tolower( ch1 ) != tolower( ch2 ) )
break;
}
else
if( ch1 != ch2 )
break;
#endif /* HAS_TOWLOWER */
str1len -= UCSIZE;
}
return( str1len ? FALSE : TRUE );
}
/* It's an ASCII string, do a straight case-insensitive comparison */
return( !strnicmp( ( char * ) str1ptr, ( char * ) str2ptr, str1len ) ? \
TRUE : FALSE );
}
/****************************************************************************
* *
* Distinguished Name Management Functions *
* *
****************************************************************************/
/* The sort order for DN components */
static int dnSortTable[] = {
0, /* countryName */
1, /* stateOrProvinceName */
2, /* locationName */
3, /* organizationName */
4, /* organizationalUnitName */
5 /* commonName */
};
#define dnSortOrder( value ) \
dnSortTable[ ( value ) - CRYPT_CERTINFO_COUNTRYNAME ]
/* A macro to make make declaring DN OID's simpler */
#define MKDNOID( value ) ( ( const BYTE * ) "\x06\x03" value )
/* Type information for DN components */
typedef struct {
const CRYPT_ATTRIBUTE_TYPE type;/* cryptlib type */
const BYTE *oid; /* OID for this type */
const char *name, *altName; /* Name for this type */
const int maxLength; /* Maximum allowed length for this type */
const BOOLEAN IA5OK; /* Whether IA5 is allowed for this comp.*/
} DN_COMPONENT_INFO;
static const DN_COMPONENT_INFO certInfoOIDs[] = {
/* Useful components */
{ CRYPT_CERTINFO_COMMONNAME, MKDNOID( "\x55\x04\x03" ), "cn", "oid.2.5.4.3", CRYPT_MAX_TEXTSIZE, FALSE },
{ CRYPT_CERTINFO_COUNTRYNAME, MKDNOID( "\x55\x04\x06" ), "c", "oid.2.5.4.6", 2, FALSE },
{ CRYPT_CERTINFO_LOCALITYNAME, MKDNOID( "\x55\x04\x07" ), "l", "oid.2.5.4.7", 128, FALSE },
{ CRYPT_CERTINFO_STATEORPROVINCENAME, MKDNOID( "\x55\x04\x08" ), "sp", "oid.2.5.4.8", 128, FALSE },
{ CRYPT_CERTINFO_ORGANIZATIONNAME, MKDNOID( "\x55\x04\x0A" ), "o", "oid.2.5.4.10", CRYPT_MAX_TEXTSIZE, FALSE },
{ CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, MKDNOID( "\x55\x04\x0B" ), "ou", "oid.2.5.4.11", CRYPT_MAX_TEXTSIZE, FALSE },
/* Non-useful components */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x01" ), "oid.2.5.4.1", NULL, CRYPT_MAX_TEXTSIZE, FALSE },
/* aliasObjectName (2 5 4 1) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x02" ), "oid.2.5.4.2", NULL, MAX_ATTRIBUTE_SIZE /*32768*/, FALSE },
/* knowledgeInformation (2 5 4 2) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x04" ), "s", "oid.2.5.4.4", CRYPT_MAX_TEXTSIZE, FALSE },
/* surname (2 5 4 4) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x05" ), "sn", "oid.2.5.4.5", CRYPT_MAX_TEXTSIZE, FALSE },
/* serialNumber (2 5 4 5) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x09" ), "st", "oid.2.5.4.9", 128, FALSE },
/* streetAddress (2 5 4 9) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x0C" ), "t", "oid.2.5.4.12", CRYPT_MAX_TEXTSIZE, FALSE },
/* title (2 5 4 12) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x0D" ), "d", "oid.2.5.4.13", 1024, FALSE },
/* description (2 5 4 13) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x0E" ), "oid.2.5.4.14", NULL, CRYPT_MAX_TEXTSIZE, FALSE },
/* searchGuide (2 5 4 14) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x0F" ), "bc", "oid.2.5.4.15", 128, FALSE },
/* businessCategory (2 5 4 15) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x10" ), "oid.2.5.4.16", NULL, CRYPT_MAX_TEXTSIZE, FALSE },
/* postalAddress (2 5 4 16) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x11" ), "oid.2.5.4.17", NULL, 40, FALSE },
/* postalCode (2 5 4 17) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x12" ), "oid.2.5.4.18", NULL, 40, FALSE },
/* postOfficeBox (2 5 4 18) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x13" ), "oid.2.5.4.19", NULL, 128, FALSE },
/* physicalDeliveryOfficeName (2 5 4 19) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x14" ), "oid.2.5.4.20", NULL, 32, FALSE },
/* telephoneNumber (2 5 4 20) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x15" ), "oid.2.5.4.21", NULL, 14, FALSE },
/* telexNumber (2 5 4 21) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x16" ), "oid.2.5.4.22", NULL, 24, FALSE },
/* teletexTerminalIdentifier (2 5 4 22) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x17" ), "oid.2.5.4.23", NULL, 32, FALSE },
/* facsimileTelephoneNumber (2 5 4 23) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x18" ), "oid.2.5.4.24", NULL, 15, FALSE },
/* x121Address (2 5 4 24) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x19" ), "isdn", "oid.2.5.4.25", 16, FALSE },
/* internationalISDNNumber (2 5 4 25) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x1A" ), "oid.2.5.4.26", NULL, CRYPT_MAX_TEXTSIZE, FALSE },
/* registeredAddress (2 5 4 26) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x1B" ), "oid.2.5.4.27", NULL, 128, FALSE },
/* destinationIndicator (2 5 4 27) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x1C" ), "oid.2.5.4.28", NULL, CRYPT_MAX_TEXTSIZE, FALSE },
/* preferredDeliveryMethod (2 5 4 28) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x1D" ), "oid.2.5.4.29", NULL, CRYPT_MAX_TEXTSIZE, FALSE },
/* presentationAddress (2 5 4 29) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x1E" ), "oid.2.5.4.30", NULL, CRYPT_MAX_TEXTSIZE, FALSE },
/* supportedApplicationContext (2 5 4 30) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x1F" ), "oid.2.5.4.31", NULL, CRYPT_MAX_TEXTSIZE, FALSE },
/* member (2 5 4 31) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x20" ), "oid.2.5.4.32", NULL, CRYPT_MAX_TEXTSIZE, FALSE },
/* owner (2 5 4 32) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x21" ), "oid.2.5.4.33", NULL, CRYPT_MAX_TEXTSIZE, FALSE },
/* roleOccupant (2 5 4 33) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x22" ), "oid.2.5.4.34", NULL, CRYPT_MAX_TEXTSIZE, FALSE },
/* seeAlso (2 5 4 34) */
/* 0x23-0x28 are certs/CRLs */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x29" ), "oid.2.5.4.41", NULL, MAX_ATTRIBUTE_SIZE /*32768*/, FALSE },
/* name (2 5 4 41) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x2A" ), "g", "oid.2.5.4.42", CRYPT_MAX_TEXTSIZE, FALSE },
/* givenName (2 5 4 42) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x2B" ), "i", "oid.2.5.4.43", CRYPT_MAX_TEXTSIZE, FALSE },
/* initials (2 5 4 43) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x2C" ), "oid.2.5.4.44", NULL, CRYPT_MAX_TEXTSIZE, FALSE },
/* generationQualifier (2 5 4 44) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x2D" ), "oid.2.5.4.45", NULL, CRYPT_MAX_TEXTSIZE, FALSE },
/* uniqueIdentifier (2 5 4 45) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x2E" ), "oid.2.5.4.46", NULL, CRYPT_MAX_TEXTSIZE, FALSE },
/* dnQualifier (2 5 4 46) */
/* 0x2F-0x30 are directory components */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x31" ), "oid.2.5.4.49", NULL, CRYPT_MAX_TEXTSIZE, FALSE },
/* distinguishedName (2 5 4 49) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x32" ), "oid.2.5.4.50", NULL, CRYPT_MAX_TEXTSIZE, FALSE },
/* uniqueMember (2 5 4 50) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x33" ), "oid.2.5.4.51", NULL, CRYPT_MAX_TEXTSIZE, FALSE },
/* houseIdentifier (2 5 4 51) */
/* 0x34-0x3A are more certs and some weird encrypted directory components */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x41" ), "oid.2.5.4.65", NULL, 128, FALSE },
/* pseudonym (2 5 4 65) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x42" ), "oid.2.5.4.66", NULL, CRYPT_MAX_TEXTSIZE, FALSE },
/* communicationsService (2 5 4 66) */
{ CRYPT_ATTRIBUTE_NONE, MKDNOID( "\x55\x04\x43" ), "oid.2.5.4.67", NULL, CRYPT_MAX_TEXTSIZE, FALSE },
/* communicationsNetwork (2 5 4 67) */
{ CRYPT_ATTRIBUTE_NONE, ( const BYTE * ) "\x06\x0A\x09\x92\x26\x89\x93\xF2\x2C\x64\x01\x03", "oid.0.9.2342.19200300.100.1.3", NULL, CRYPT_MAX_TEXTSIZE, TRUE },
/* rfc822Mailbox (0 9 2342 19200300 100 1 3) */
{ CRYPT_ATTRIBUTE_NONE, ( const BYTE * ) "\x06\x0A\x09\x92\x26\x89\x93\xF2\x2C\x64\x01\x01", "dc", "oid.0.9.2342.19200300.100.1.25", CRYPT_MAX_TEXTSIZE, TRUE },
/* domainComponent (0 9 2342 19200300 100 1 25) */
{ CRYPT_ATTRIBUTE_NONE, ( const BYTE * ) "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01", "email", "oid.1.2.840.113549.1.9.1", CRYPT_MAX_TEXTSIZE, TRUE },
/* emailAddress (1 2 840 113549 1 9 1) */
{ CRYPT_ATTRIBUTE_NONE, ( const BYTE * ) "\x06\x07\x02\x82\x06\x01\x0A\x07\x14", "oid.0.2.262.1.10.7.20", NULL, CRYPT_MAX_TEXTSIZE, TRUE },
/* nameDistinguisher (0 2 262 1 10 7 20) */
{ CRYPT_ATTRIBUTE_NONE, NULL }
} ;
/* If the OID doesn't correspond to a valid cryptlib component (ie it's one
of the 1,001 other odd things which can be crammed into a DN), we can't
directly identify it with a type but instead return the index in the OID
info table, offset by a suitable amount */
#define DN_OID_OFFSET 10000
/* Check that a country code is valid */
static BOOLEAN checkCountryCode( const char *countryCode )
{
const static char *countryCodes[] = {
"AD", "AE", "AF", "AG", "AI", "AL", "AM", "AN", "AO", "AQ",
"AR", "AS", "AT", "AU", "AW", "AZ", "BA", "BB", "BD", "BE",
"BF", "BG", "BH", "BI", "BJ", "BM", "BN", "BO", "BR", "BS",
"BT", "BV", "BW", "BY", "BZ", "CA", "CC", "CF", "CG", "CH",
"CI", "CK", "CL", "CM", "CN", "CO", "CR", "CU", "CV", "CX",
"CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE",
"EG", "EH", "ER", "ES", "ET", "FI", "FJ", "FK", "FM", "FO",
"FR", "FX", "GA", "GB", "GD", "GE", "GF", "GH", "GI", "GL",
"GM", "GN", "GP", "GQ", "GR", "GS", "GT", "GU", "GW", "GY",
"HK", "HM", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN",
"IO", "IQ", "IR", "IS", "IT", "JM", "JO", "JP", "KE", "KG",
"KH", "KI", "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA",
"LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY",
"MA", "MC", "MD", "MG", "MH", "MK", "ML", "MM", "MN", "MO",
"MP", "MQ", "MR", "MS", "MT", "MU", "MV", "MW", "MX", "MY",
"MZ", "NA", "NC", "NE", "NF", "NG", "NI", "NL", "NO", "NP",
"NR", "NU", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK",
"PL", "PM", "PN", "PR", "PT", "PW", "PY", "QA", "RE", "RO",
"RU", "RW", "SA", "SB", "SC", "SD", "SE", "SG", "SH", "SI",
"SJ", "SK", "SL", "SM", "SN", "SO", "SR", "ST", "SV", "SY",
"SZ", "TC", "TD", "TF", "TG", "TH", "TJ", "TK", "TM", "TN",
"TO", "TP", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UM",
"US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI", "VN", "VU",
"WF", "WS", "YE", "YT", "YU", "ZA", "ZM", "ZR", "ZW", NULL
};
int i;
/* Check that the country code is present in the table of known codes */
for( i = 0; countryCodes[ i ] != NULL; i++ )
if( !strcmp( countryCode, countryCodes[ i ] ) )
return( TRUE );
return( FALSE );
}
/* Find a DN component in a DN component list by type and by OID */
static DN_COMPONENT *findDNComponent( const void *dnListHead,
const CRYPT_ATTRIBUTE_TYPE type,
const void *value,
const int valueLength )
{
DN_COMPONENT *listPtr = ( DN_COMPONENT * ) dnListHead;
/* Find the position of this component in the list */
while( listPtr != NULL )
{
if( listPtr->type == type && \
( ( value == NULL ) || \
( listPtr->valueLength == valueLength && \
!memcmp( listPtr->value, value, valueLength ) ) ) )
break;
listPtr = listPtr->next;
}
return( listPtr );
}
static DN_COMPONENT *findDNComponentByOID( const void *dnListHead,
const BYTE *oid )
{
DN_COMPONENT *listPtr = ( DN_COMPONENT * ) dnListHead;
const int oidLen = sizeofOID( oid );
/* Find the position of this component in the list */
while( listPtr != NULL )
{
const DN_COMPONENT_INFO *dnComponentInfo = listPtr->typeInfo;
if( !memcmp( dnComponentInfo->oid, oid, oidLen ) )
break;
listPtr = listPtr->next;
}
return( listPtr );
}
/* Insert a DN component into a list. If the type is zero then it's an
unrecognised component type, and if it's negative it's a recognised
component type being read from a cert produced by a non-cryptlib
application. In this case we don't try to sort the component into the
correct position */
static void insertListElement( void **dnListHeadPtr,
DN_COMPONENT *insertPoint,
DN_COMPONENT *newElement )
{
/* If it's an empty list, make this the new list */
if( *dnListHeadPtr == NULL )
{
*dnListHeadPtr = newElement;
return;
}
/* If we're inserting at the start of the list, make this the new first
element */
if( insertPoint == NULL )
{
DN_COMPONENT *listHeadPtr = *dnListHeadPtr;
/* Insert the element at the start of the list */
newElement->next = listHeadPtr;
listHeadPtr->prev = newElement;
*dnListHeadPtr = newElement;
return;
}
/* Insert the element in the middle or end of the list. Update the links
for the next element */
newElement->next = insertPoint->next;
if( insertPoint->next != NULL )
insertPoint->next->prev = newElement;
/* Update the links for the previous element */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -