📄 certdn.c
字号:
****************************************************************************/
/* 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 int insertDNstring( void **dnListHead, const CRYPT_ATTRIBUTE_TYPE type,
const void *value, const int valueLength,
const int flags, CRYPT_ERRTYPE_TYPE *errorType )
{
const DN_COMPONENT_INFO *dnComponentInfo;
DN_COMPONENT *listHeadPtr = *dnListHead;
DN_COMPONENT *newElement, *insertPoint;
/* 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 );
/* 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;
}
if( certInfoOIDs[ i ].type == CRYPT_ATTRIBUTE_NONE )
{
assert( NOTREACHED );
return( CRYPT_ERROR_NOTAVAIL );
}
}
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 * ) value;
#else
dnComponentInfo = &certInfoOIDs[ type - DN_OID_OFFSET ];
#endif /* gcc 2.7.x bug workaround */
if( type - DN_OID_OFFSET >= \
sizeof( certInfoOIDs ) / sizeof( DN_COMPONENT_INFO ) )
{
assert( NOTREACHED );
return( CRYPT_ERROR_NOTAVAIL );
}
}
/* Make sure that 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. In addition if a
widechar string is OK we allow a range up to the maximum byte count
defined by the widechar size, this is only valid for standard DN
components, when they're coming from the user the exact check has
already been performed by the kernel */
#ifdef USE_WIDECHARS
if( valueLength > ( ( flags & DN_FLAG_NOCHECK ) ? \
MAX_ATTRIBUTE_SIZE : \
( dnComponentInfo->wcsOK ) ? \
( WCSIZE * dnComponentInfo->maxLength ) : \
dnComponentInfo->maxLength ) )
#else
if( valueLength > ( ( flags & DN_FLAG_NOCHECK ) ? \
MAX_ATTRIBUTE_SIZE : dnComponentInfo->maxLength ) )
#endif /* USE_WIDECHARS */
{
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 * ) \
clAlloc( "insertDNstring", sizeof( DN_COMPONENT ) + \
valueLength ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
initVarStruct( newElement, DN_COMPONENT, valueLength );
newElement->type = type;
newElement->typeInfo = dnComponentInfo;
memcpy( newElement->value, value, valueLength );
newElement->valueLength = valueLength;
newElement->flags = flags;
/* If it's a country code, force it to uppercase as per ISO 3166 */
if( type == CRYPT_CERTINFO_COUNTRYNAME )
{
BYTE *dnStrPtr = newElement->value;
dnStrPtr[ 0 ] = toUpper( dnStrPtr[ 0 ] );
dnStrPtr[ 1 ] = toUpper( dnStrPtr[ 1 ] );
if( flags & DN_FLAG_NOCHECK )
{
/* 'UK' isn't an ISO 3166 country code but may be found in some
certificates. If we find this, we quietly convert it to the
correct value */
if( !memcmp( newElement->value, "UK", 2 ) )
memcpy( newElement->value, "GB", 2 );
}
else
/* Make sure the country code is valid */
if( !checkCountryCode( ( char * ) newElement->value ) )
{
endVarStruct( newElement, DN_COMPONENT );
clFree( "insertDNstring", newElement );
if( errorType != NULL )
*errorType = CRYPT_ERRTYPE_ATTR_VALUE;
return( CRYPT_ERROR_INVALID );
}
}
/* Link it into the list */
insertDoubleListElement( ( DN_COMPONENT ** ) 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,
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 );
assert( isWritePtr( theElement, DN_COMPONENT ) );
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 */
endVarStruct( theElement, DN_COMPONENT );
clFree( "deleteComponent", 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 ) ) );
}
/* Delete a DN */
void deleteDN( void **dnListHead )
{
DN_COMPONENT *listPtr = *dnListHead;
/* Mark the list as being empty */
*dnListHead = NULL;
/* Destroy all DN items */
while( listPtr != NULL )
{
DN_COMPONENT *itemToFree = listPtr;
listPtr = listPtr->next;
deleteComponent( ( void ** ) &itemToFree, itemToFree );
}
}
/* 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 );
}
/* Compare two DNs. 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 DNs don't match */
if( dn1ptr->type != dn2ptr->type )
return( FALSE );
/* Compare the current RDNs. In theory we should be using the
complex and arcane X.500 name comparison rules, but no-one
actually does this since they're almost impossible to get right.
Since everyone else uses memcpy()/memcmp() to handle DN
components, it's safe to use it here (sic faciunt omnes). This
also avoids any potential security problems arising from the
complexity of the code necessary to implement the X.500 matching
rules */
if( dn1ptr->valueLength != dn2ptr->valueLength || \
memcmp( dn1ptr->value, dn2ptr->value, dn1ptr->valueLength ) )
return( FALSE );
/* Move on to the next component */
dn1ptr = dn1ptr->next;
dn2ptr = dn2ptr->next;
}
/* If we've reached the end of both DNs 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;
/* Allocate memory for the new element and copy over the information */
if( ( newElement = ( DN_COMPONENT * ) \
clAlloc( "copyDN", \
sizeofVarStruct( srcPtr, DN_COMPONENT ) ) ) == NULL )
{
deleteDN( dnDest );
return( CRYPT_ERROR_MEMORY );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -