📄 certstr.c
字号:
insertPoint->next = newElement;
newElement->prev = insertPoint;
}
static int insertDNstring( void **dnListHead, const CRYPT_ATTRIBUTE_TYPE type,
const void *value, const int valueLength,
const ASN1_STRINGTYPE stringType, const int flags,
CRYPT_ERRTYPE_TYPE *errorType )
{
const DN_COMPONENT_INFO *dnComponentInfo;
DN_COMPONENT *listHeadPtr = *dnListHead;
DN_COMPONENT *newElement, *insertPoint;
ASN1_STRINGTYPE dnStringType = stringType;
BYTE dnString[ ( CRYPT_MAX_TEXTSIZE + 1 ) * 2 ];
const void *dnStringPtr = value;
int dnStringLength = valueLength;
/* If the DN is locked against modification we can't make any further
updates */
if( listHeadPtr != NULL && listHeadPtr->flags & DN_FLAG_LOCKED )
return( CRYPT_ERROR_INITED );
/* If we've been fed the string from an external source, copy the string
to the internal format */
if( !( flags & DN_FLAG_NOCHECK ) )
{
dnStringType = copyConvertString( value, valueLength, dnString,
&dnStringLength, CRYPT_MAX_TEXTSIZE,
FALSE, FALSE );
if( dnStringType == STRINGTYPE_NONE )
{
/* The copy can only fail if the data is too large */
*errorType = CRYPT_ERRTYPE_ATTR_SIZE;
return( CRYPT_ARGERROR_NUM1 );
}
dnStringPtr = dnString;
}
/* Find the type information for this component if it's a recognised
type */
if( type > CRYPT_CERTINFO_FIRST && type < CRYPT_CERTINFO_LAST )
{
int i;
/* It's a handled component, get the pointer to the OID */
for( i = 0; certInfoOIDs[ i ].type != CRYPT_ATTRIBUTE_NONE; i++ )
if( certInfoOIDs[ i ].type == type )
{
dnComponentInfo = &certInfoOIDs[ i ];
break;
}
assert( certInfoOIDs[ i ].type != CRYPT_ATTRIBUTE_NONE );
}
else
/* It's a non-handled component, the type is an index into the
component table. At this point we run into a GCC 2.7.x compiler
bug (detect with '#if defined( __GNUC__ ) && ( __GNUC__ == 2 )').
If we use the expression '&certInfoOIDs[ type - DN_OID_OFFSET ]'
what we should get is:
leal -1000(%ebp,%ebp,2),%eax
movl certInfoOIDs(,%eax,4),%eax
but what we actually get is:
leal -3000(%ebp,%ebp,2),%eax
movl certInfoOIDs(,%eax,4),%eax
To fix this we need to insert some form of dummy evaluation in a
form which ensures that it can't be optimised away (which is
actually quite difficult with gcc because it optimises any simple
code way). To work around this we insert a dummy expression to
keep the value live */
{
#if defined( __GNUC__ ) && ( __GNUC__ == 2 )
int i = type - DN_OID_OFFSET;
dnComponentInfo = &certInfoOIDs[ i ];
if( dnComponentInfo < 0 ) /* Dummy code to keep i live */
newElement = ( i + type ) ? NULL : ( void * ) dnStringPtr;
#else
dnComponentInfo = &certInfoOIDs[ type - DN_OID_OFFSET ];
#endif /* gcc 2.7.x bug workaround */
assert( type - DN_OID_OFFSET < \
sizeof( certInfoOIDs ) / sizeof( DN_COMPONENT_INFO ) );
}
/* Make sure the length is valid. If it's being read from an encoded
form we allow abnormally-long lengths (although we still keep them
within a sensible limit) since this is better than failing to read a
cert because it contains a broken DN */
if( dnStringLength > ( ( flags & DN_FLAG_NOCHECK ) ? MAX_ATTRIBUTE_SIZE : \
( dnStringType == STRINGTYPE_UNICODE ) ? \
dnComponentInfo->maxLength * 2 : \
dnComponentInfo->maxLength ) )
{
if( errorType != NULL )
*errorType = CRYPT_ERRTYPE_ATTR_SIZE;
return( CRYPT_ARGERROR_NUM1 );
}
/* Find the correct place in the list to insert the new element */
if( listHeadPtr != NULL )
{
DN_COMPONENT *prevElement = NULL;
/* If it's being read from an external cert item, just append it to
the end of the list */
if( flags & DN_FLAG_NOCHECK )
for( insertPoint = listHeadPtr; insertPoint->next != NULL;
insertPoint = insertPoint->next );
else
{
for( insertPoint = listHeadPtr; insertPoint != NULL && \
dnSortOrder( type ) >= dnSortOrder( insertPoint->type );
insertPoint = insertPoint->next )
{
/* Make sure this component isn't already present. For now
we only allow a single DN component of any type to keep
things simple for the user, if it's necessary to allow
multiple components of the same type we need to check the
value and valueLength as well */
if( insertPoint->type == type )
{
if( errorType != NULL )
*errorType = CRYPT_ERRTYPE_ATTR_PRESENT;
return( CRYPT_ERROR_INITED );
}
prevElement = insertPoint;
}
insertPoint = prevElement;
}
}
/* Allocate memory for the new element and copy over the information */
if( ( newElement = ( DN_COMPONENT * ) malloc( sizeof( DN_COMPONENT ) ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
memset( newElement, 0, sizeof( DN_COMPONENT ) );
newElement->type = type;
newElement->stringType = dnStringType;
newElement->typeInfo = dnComponentInfo;
if( dnStringLength > CRYPT_MAX_TEXTSIZE )
{
if( ( newElement->value = malloc( dnStringLength ) ) == NULL )
{
free( newElement );
return( CRYPT_ERROR_MEMORY );
}
}
else
newElement->value = newElement->smallValue;
memcpy( newElement->value, dnStringPtr, dnStringLength );
newElement->valueLength = dnStringLength;
newElement->flags = flags;
/* If it's a country code supplied by the user, force it to uppercase as
per ISO 3166 */
if( type == CRYPT_CERTINFO_COUNTRYNAME )
{
newElement->smallValue[ 0 ] = toupper( newElement->smallValue[ 0 ] );
newElement->smallValue[ 1 ] = toupper( newElement->smallValue[ 1 ] );
if( !checkCountryCode( ( char * ) newElement->smallValue ) )
{
free( newElement );
if( errorType != NULL )
*errorType = CRYPT_ERRTYPE_ATTR_VALUE;
return( CRYPT_ERROR_INVALID );
}
}
/* If we're reading an encoded 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( ( flags & DN_FLAG_NOCHECK ) && dnStringType == STRINGTYPE_T61 )
{
BYTE *valuePtr = newElement->value;
int i;
for( i = 0; i < newElement->valueLength - 1; i++ )
if( valuePtr[ i ] == 0xC8 )
{
int ch = valuePtr[ 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 == 'a' || ch == 'A' || ch == 'o' || ch == 'O' || \
ch == 'u' || ch == 'U' )
{
valuePtr[ i ] = valuePtr[ i + 1 ] + \
( ( ch == 'a' || ch == 'A' ) ? 131 : 135 );
if( ch >= 'a' )
valuePtr[ i ] += 32;
if( newElement->valueLength - i > 2 )
memmove( valuePtr + i + 1, valuePtr + i + 2,
newElement->valueLength - ( i + 2 ) );
newElement->valueLength--;
}
}
valuePtr[ newElement->valueLength ] = '\0';
}
/* Link it into the list */
insertListElement( dnListHead, insertPoint, newElement );
return( CRYPT_OK );
}
int insertDNComponent( void **dnListHead,
const CRYPT_ATTRIBUTE_TYPE type,
const void *value, const int valueLength,
CRYPT_ERRTYPE_TYPE *errorType )
{
return( insertDNstring( dnListHead, type, value, valueLength, 0, 0,
errorType ) );
}
/* Delete a DN component from a list */
static int deleteComponent( void **dnListHead, DN_COMPONENT *theElement )
{
DN_COMPONENT *listPrevPtr, *listNextPtr;
if( theElement == NULL )
return( CRYPT_ERROR_NOTFOUND );
listPrevPtr = theElement->prev;
listNextPtr = theElement->next;
/* Remove the item from the list */
if( theElement == *dnListHead )
*dnListHead = listNextPtr; /* Delete from start */
else
listPrevPtr->next = listNextPtr; /* Delete from middle or end */
if( listNextPtr != NULL )
listNextPtr->prev = listPrevPtr;
/* Clear all data in the list item and free the memory */
if( theElement->value != theElement->smallValue )
{
zeroise( theElement->value, theElement->valueLength );
free( theElement->value );
}
zeroise( theElement, sizeof( DN_COMPONENT ) );
free( theElement );
return( CRYPT_OK );
}
int deleteDNComponent( void **dnListHead,
const CRYPT_ATTRIBUTE_TYPE type, const void *value,
const int valueLength )
{
DN_COMPONENT *listHeadPtr = *dnListHead;
/* If the DN is locked against modification we can't make any further
updates */
if( listHeadPtr != NULL && listHeadPtr->flags & DN_FLAG_LOCKED )
return( CRYPT_ERROR_PERMISSION );
/* Find the component in the list and delete it */
return( deleteComponent( dnListHead, findDNComponent( listHeadPtr, type,
value, valueLength ) ) );
}
/* Get the value of a DN component */
int getDNComponentValue( const void *dnListHead,
const CRYPT_ATTRIBUTE_TYPE type,
void *value, int *length, const int maxLength )
{
const DN_COMPONENT *dnComponent = findDNComponent( dnListHead, type,
NULL, 0 );
if( dnComponent == NULL )
return( CRYPT_ERROR_NOTFOUND );
*length = dnComponent->valueLength;
if( value == NULL )
return( CRYPT_OK );
if( dnComponent->valueLength > maxLength )
return( CRYPT_ERROR_OVERFLOW );
if( checkBadPtrWrite( value, dnComponent->valueLength ) )
return( CRYPT_ARGERROR_STR1 );
memcpy( value, dnComponent->value, dnComponent->valueLength );
return( CRYPT_OK );
}
/* Delete a DN component list */
void deleteDN( void **dnListHead )
{
DN_COMPONENT *listPtr = *dnListHead;
/* Mark the list as being empty */
*dnListHead = NULL;
/* If the list was empty, return now */
if( listPtr == NULL )
return;
/* Destroy any remaining list items */
while( listPtr != NULL )
{
DN_COMPONENT *itemToFree = listPtr;
listPtr = listPtr->next;
if( itemToFree->value != itemToFree->smallValue )
{
zeroise( itemToFree->value, itemToFree->valueLength );
free( itemToFree->value );
}
zeroise( itemToFree, sizeof( DN_COMPONENT ) );
free( itemToFree );
}
}
/* Compare two DN's. Since this is used for constraint comparisons as well
as just strict equality checks, we provide a flag which, if set, returns
a match if the first DN is a proper substring of the second DN */
BOOLEAN compareDN( const void *dnComponentListHead1,
const void *dnComponentListHead2,
const BOOLEAN dn1substring )
{
DN_COMPONENT *dn1ptr = ( DN_COMPONENT * ) dnComponentListHead1;
DN_COMPONENT *dn2ptr = ( DN_COMPONENT * ) dnComponentListHead2;
/* Check each DN component for equality */
while( dn1ptr != NULL && dn2ptr != NULL )
{
/* If the RDN types differ, the DN's don't match */
if( dn1ptr->type != dn2ptr->type )
return( FALSE );
/* Compare the current RDN's */
if( !compareASN1string( dn1ptr->value, dn1ptr->valueLength,
dn2ptr->value, dn2ptr->valueLength ) )
return( FALSE );
/* Move on to the next component */
dn1ptr = dn1ptr->next;
dn2ptr = dn2ptr->next;
}
/* If we've reached the end of both DN's or we're looking for a substring
match, the two match */
return( ( ( dn1ptr == NULL && dn2ptr == NULL ) || dn1substring ) ? \
TRUE : FALSE );
}
/* Copy a DN */
int copyDN( void **dnDest, const void *dnSrc )
{
const DN_COMPONENT *srcPtr = dnSrc;
DN_COMPONENT *destPtr = NULL;
for( *dnDest = NULL; srcPtr != NULL; srcPtr = srcPtr->next )
{
DN_COMPONENT *newElement;
void *valuePtr;
/* Allocate memory for the new element and copy over the information */
if( ( ( newElement = \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -