📄 certext.c
字号:
switch( attributeInfoPtr->fieldType )
{
case FIELDTYPE_BLOB:
/* It's a blob field, make sure that it's a valid ASN.1 object */
if( cryptStatusError( getObjectLength( data, dataLength ) ) )
{
if( errorType != NULL )
*errorType = CRYPT_ERRTYPE_ATTR_VALUE;
return( CRYPT_ARGERROR_STR1 );
}
return( CRYPT_OK );
case BER_STRING_NUMERIC:
{
const char *dataPtr = data;
int i;
/* Make sure it's a numeric string */
for( i = 0; i < dataLength; i++ )
if( !isDigit( dataPtr[ i ] ) )
{
if( errorType != NULL )
*errorType = CRYPT_ERRTYPE_ATTR_VALUE;
return( CRYPT_ARGERROR_STR1 );
}
return( CRYPT_OK );
}
case BER_STRING_IA5:
case BER_STRING_ISO646:
case BER_STRING_PRINTABLE:
/* Make sure it's an ASCII string of the correct type */
if( !checkTextStringData( data, dataLength,
( attributeInfoPtr->fieldType == BER_STRING_PRINTABLE ) ? \
TRUE : FALSE ) )
{
if( errorType != NULL )
*errorType = CRYPT_ERRTYPE_ATTR_VALUE;
return( CRYPT_ARGERROR_STR1 );
}
return( CRYPT_OK );
}
return( CRYPT_OK );
}
/* Add an attribute field to a list of attributes at the appropriate
location */
int addAttributeField( ATTRIBUTE_LIST **attributeListPtr,
const CRYPT_ATTRIBUTE_TYPE fieldID,
const CRYPT_ATTRIBUTE_TYPE subFieldID,
const void *data, const int dataLength,
const int flags, CRYPT_ATTRIBUTE_TYPE *errorLocus,
CRYPT_ERRTYPE_TYPE *errorType )
{
const ATTRIBUTE_TYPE attributeType = \
( fieldID >= CRYPT_CERTINFO_FIRST_CMS ) ? \
ATTRIBUTE_CMS : ATTRIBUTE_CERTIFICATE;
CRYPT_ATTRIBUTE_TYPE attributeID;
const ATTRIBUTE_INFO *attributeInfoPtr = fieldIDToAttribute( attributeType,
fieldID, subFieldID, &attributeID );
ATTRIBUTE_LIST *newElement, *insertPoint, *prevElement = NULL;
BOOLEAN isNumeric = FALSE;
int storageSize, status;
assert( isWritePtr( attributeListPtr, ATTRIBUTE_LIST * ) );
assert( dataLength == CRYPT_UNUSED || \
( dataLength > 0 && dataLength <= MAX_ATTRIBUTE_SIZE ) );
assert( dataLength == CRYPT_UNUSED || \
!checkBadPtrRead( data, dataLength ) );
assert( !( flags & ATTR_FLAG_INVALID ) );
assert( isReadPtr( attributeInfoPtr, ATTRIBUTE_INFO ) );
/* Check the field's validity */
status = checkAttributeField( *attributeListPtr, attributeInfoPtr,
fieldID, subFieldID, data, dataLength,
flags, errorType );
if( cryptStatusError( status ) )
{
if( status == OK_SPECIAL )
/* Special indicator to tell us that the value is non-string
numeric data */
isNumeric = TRUE;
else
{
if( errorType != NULL && cryptStatusError( *errorType ) )
/* If we encountered an error that sets the error type,
record the locus */
*errorLocus = fieldID;
return( status );
}
}
assert( isNumeric || \
( ( attributeInfoPtr->fieldType == FIELDTYPE_DN || \
attributeInfoPtr->fieldType == FIELDTYPE_IDENTIFIER ) && \
dataLength == CRYPT_UNUSED ) || \
dataLength > 0 );
/* Find the location at which to insert this attribute field (this
assumes that the fieldIDs are defined in sorted order) */
insertPoint = *attributeListPtr;
while( insertPoint != NULL && \
insertPoint->fieldID != CRYPT_ATTRIBUTE_NONE && \
insertPoint->fieldID <= fieldID )
{
/* If it's a composite field that can have multiple fields with the
same field ID (e.g.a GeneralName), exit if the overall field ID is
greater (the component belongs to a different field entirely) or
if the field ID is the same and the subfield ID is greater (if
the component belongs to the same field) */
if( subFieldID != CRYPT_ATTRIBUTE_NONE && \
insertPoint->fieldID == fieldID && \
insertPoint->subFieldID > subFieldID )
break;
prevElement = insertPoint;
insertPoint = insertPoint->next;
}
insertPoint = prevElement;
/* Allocate memory for the new element and copy the information across.
If it's a simple type we can assign it to the simple value in the
element itself, otherwise we either copy it into the storage in the
element or allocate seperate storage and copy it into that. Something
that encodes to NULL isn't really a numeric type, but we class it as
such so that any attempt to read it returns CRYPT_UNUSED as the value */
storageSize = ( isNumeric || \
attributeInfoPtr->fieldType == FIELDTYPE_DN || \
attributeInfoPtr->fieldType == FIELDTYPE_IDENTIFIER ) ? \
0 : dataLength;
if( ( newElement = ( ATTRIBUTE_LIST * ) \
clAlloc( "addAttributeField", sizeof( ATTRIBUTE_LIST ) + \
storageSize ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
initVarStruct( newElement, ATTRIBUTE_LIST, storageSize );
newElement->attributeID = attributeID;
newElement->fieldID = fieldID;
newElement->subFieldID = subFieldID;
newElement->flags = flags;
newElement->fieldType = attributeInfoPtr->fieldType;
switch( attributeInfoPtr->fieldType )
{
case BER_INTEGER:
case BER_ENUMERATED:
case BER_BITSTRING:
case BER_BOOLEAN:
case BER_NULL:
case FIELDTYPE_CHOICE:
newElement->intValue = *( ( int * ) data );
if( attributeInfoPtr->fieldType == BER_BOOLEAN )
/* Force it to the correct type if it's a boolean */
newElement->intValue = ( newElement->intValue ) ? TRUE : FALSE;
if( attributeInfoPtr->fieldType == FIELDTYPE_CHOICE )
/* For encoding purposes the subfield ID is set to the ID of
the CHOICE selection */
newElement->subFieldID = newElement->intValue;
break;
case BER_OBJECT_IDENTIFIER:
/* If it's a BER/DER-encoded OID copy it in as is, otherwise
convert it from the text form */
if( ( ( BYTE * ) data )[ 0 ] == BER_OBJECT_IDENTIFIER )
{
memcpy( newElement->value, data, dataLength );
newElement->valueLength = dataLength;
}
else
newElement->valueLength = textToOID( data, dataLength,
newElement->value );
break;
case FIELDTYPE_DN:
/* When creating a new cert, this is a placeholder to indicate
that a DN structure is being instantiated. When reading an
encoded cert, this is the decoded DN structure */
newElement->value = ( *( ( int * ) data ) == CRYPT_UNUSED ) ? \
NULL : ( void * ) data;
break;
case FIELDTYPE_IDENTIFIER:
/* This is a placeholder entry with no explicit value */
newElement->intValue = CRYPT_UNUSED;
break;
default:
assert( dataLength > 0 );
memcpy( newElement->value, data, dataLength );
newElement->valueLength = dataLength;
break;
}
insertDoubleListElement( attributeListPtr, insertPoint, newElement );
return( CRYPT_OK );
}
/* Copy an attribute from one attribute list to another. This is an all-or-
nothing copy in that it either copies a complete attribute or nothing at
all */
static int copyAttributeField( ATTRIBUTE_LIST **destAttributeField,
const ATTRIBUTE_LIST *srcAttributeField )
{
ATTRIBUTE_LIST *newElement;
int status = CRYPT_OK;
assert( isWritePtr( destAttributeField, ATTRIBUTE_LIST * ) );
assert( isReadPtr( srcAttributeField, ATTRIBUTE_LIST ) );
/* Allocate memory for the new element and copy the information across */
*destAttributeField = NULL;
if( ( newElement = ( ATTRIBUTE_LIST * ) \
clAlloc( "copyAttributeField", \
sizeofVarStruct( srcAttributeField, \
ATTRIBUTE_LIST ) ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
copyVarStruct( newElement, srcAttributeField, ATTRIBUTE_LIST );
if( srcAttributeField->fieldType == FIELDTYPE_DN )
{
/* If the field contains a DN, copy the DN across */
status = copyDN( ( void ** ) &newElement->value,
srcAttributeField->value );
if( cryptStatusError( status ) )
{
endVarStruct( newElement, ATTRIBUTE_LIST );
clFree( "copyAttributeField", newElement );
return( status );
}
}
newElement->next = newElement->prev = NULL;
*destAttributeField = newElement;
return( CRYPT_OK );
}
static int copyAttribute( ATTRIBUTE_LIST **destListHeadPtr,
const ATTRIBUTE_LIST *srcListPtr,
const BOOLEAN subjectToIssuer )
{
const CRYPT_ATTRIBUTE_TYPE attributeID = srcListPtr->attributeID;
CRYPT_ATTRIBUTE_TYPE newAttributeID = attributeID, newFieldID = attributeID;
ATTRIBUTE_LIST *newAttributeListHead = NULL, *newAttributeListTail;
ATTRIBUTE_LIST *insertPoint, *prevElement = NULL;
assert( isWritePtr( destListHeadPtr, ATTRIBUTE_LIST * ) );
assert( isReadPtr( srcListPtr, ATTRIBUTE_LIST ) );
/* If we're copying from an issuer to a subject attribute list and the
field is an altName or keyIdentifier, change the field type from
issuer.subjectAltName to subject.issuerAltName or
issuer.subjectKeyIdentifier to subject.authorityKeyIdentifier */
if( subjectToIssuer )
{
if( attributeID == CRYPT_CERTINFO_SUBJECTALTNAME )
newAttributeID = newFieldID = CRYPT_CERTINFO_ISSUERALTNAME;
if( attributeID == CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER )
{
newAttributeID = CRYPT_CERTINFO_AUTHORITYKEYIDENTIFIER;
newFieldID = CRYPT_CERTINFO_AUTHORITY_KEYIDENTIFIER;
}
}
/* Find the location at which to insert this attribute. For now we
assume that the fieldIDs are defined in sorted order, we may need to
change this and add internal mapping if new fieldIDs are added out of
order */
for( insertPoint = *destListHeadPtr;
insertPoint != NULL && insertPoint->attributeID < newAttributeID && \
insertPoint->fieldID != CRYPT_ATTRIBUTE_NONE;
insertPoint = insertPoint->next )
prevElement = insertPoint;
insertPoint = prevElement;
/* Build a new attribute list containing the attribute fields */
while( srcListPtr != NULL && srcListPtr->attributeID == attributeID )
{
ATTRIBUTE_LIST *newAttributeField;
int status;
/* Copy the field across, append it to the new attribute list, and
adjust the type for issuer->subject copying if necessary */
status = copyAttributeField( &newAttributeField, srcListPtr );
if( cryptStatusError( status ) )
{
deleteAttributes( &newAttributeListHead );
return( CRYPT_ERROR_MEMORY );
}
if( newAttributeListHead == NULL )
newAttributeListHead = newAttributeListTail = newAttributeField;
else
{
newAttributeListTail->next = newAttributeField;
newAttributeField->prev = newAttributeListTail;
newAttributeListTail = newAttributeField;
}
if( newAttributeID != attributeID )
{
newAttributeField->attributeID = newAttributeID;
newAttributeField->fieldID = newFieldID;
}
/* Move on to the next field */
srcListPtr = srcListPtr->next;
}
/* Link the new list into the existing list at the appropriate position */
insertDoubleListElements( destListHeadPtr, insertPoint,
newAttributeListHead, newAttributeListTail );
return( CRYPT_OK );
}
/* Copy a complete attribute list */
int copyAttributes( ATTRIBUTE_LIST **destListHeadPtr,
ATTRIBUTE_LIST *srcListPtr,
CRYPT_ATTRIBUTE_TYPE *errorLocus,
CRYPT_ERRTYPE_TYPE *errorType )
{
ATTRIBUTE_LIST *attributeListCursor = srcListPtr;
assert( isWritePtr( destListHeadPtr, ATTRIBUTE_LIST * ) );
assert( isReadPtr( srcListPtr, ATTRIBUTE_LIST ) );
/* Make a first pass down the list checking that the attribute to copy
isn't already present, first for recognised attributes and then for
unrecognised ones. We have to do this separately since once we begin
the copy process it's rather hard to undo it. Note that in theory
there are some attributes that can have multiple instances of a field
present, which means we could allow them to appear in both the source
and destination lists, however if this occurs it's more likely to be
an error than a desire to merge two disparate collections of
attributes */
while( attributeListCursor != NULL && \
!isBlobAttribute( attributeListCursor ) )
{
if( findAttributeField( *destListHeadPtr,
attributeListCursor->fieldID, CRYPT_ATTRIBUTE_NONE ) != NULL )
{
*errorLocus = attributeListCursor->fieldID;
*errorType = CRYPT_ERRTYPE_ATTR_PRESENT;
return( CRYPT_ERROR_DUPLICATE );
}
attributeListCursor = attributeListCursor->next;
}
while( attributeListCursor != NULL )
{
assert( isBlobAttribute( attributeListCursor ) );
if( findAttributeByOID( *destListHeadPtr, attributeListCursor->oid ) != NULL )
{
/* We can't set the locus for blob-type attributes since it's not
a known attribute */
*errorLocus = CRYPT_ATTRIBUTE_NONE;
*errorType = CRYPT_ERRTYPE_ATTR_PRESENT;
return( CRYPT_ERROR_DUPLICATE );
}
attributeListCursor = attributeListCursor->next;
}
/* Make a second pass copying everything across */
while( srcListPtr != NULL && !isBlobAttribute( srcListPtr ) )
{
CRYPT_ATTRIBUTE_TYPE attributeID = srcListPtr->attributeID;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -