📄 ext_add.c
字号:
IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE fieldID,
IN_ATTRIBUTE_OPT const CRYPT_ATTRIBUTE_TYPE subFieldID,
/*?*/ const void *data,
/*?*/ const int dataLength,
IN_FLAGS_Z( ATTR ) const int flags,
OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
CRYPT_ATTRIBUTE_TYPE *errorLocus,
OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
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;
CHECKATTR_INFO_TYPE infoType;
int storageSize, newDataLength, iterationCount, status;
assert( isWritePtr( attributeListPtr, sizeof( ATTRIBUTE_LIST * ) ) );
assert( dataLength == CRYPT_UNUSED || isReadPtr( data, dataLength ) );
assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
assert( isReadPtr( attributeInfoPtr, sizeof( ATTRIBUTE_INFO ) ) );
REQUIRES( fieldID >= CRYPT_CERTINFO_FIRST_EXTENSION && \
fieldID <= CRYPT_CERTINFO_LAST );
REQUIRES( subFieldID == CRYPT_ATTRIBUTE_NONE || \
( subFieldID >= CRYPT_CERTINFO_FIRST_NAME && \
subFieldID <= CRYPT_CERTINFO_LAST_GENERALNAME ) );
REQUIRES( dataLength == CRYPT_UNUSED || \
( data != NULL && \
dataLength > 0 && dataLength <= MAX_ATTRIBUTE_SIZE ) );
assert( ( flags & ~( ATTR_FLAG_BLOB_PAYLOAD | ATTR_FLAG_CRITICAL | ATTR_FLAG_MULTIVALUED | ATTR_FLAG_BLOB_PAYLOAD ) ) == 0 );
REQUIRES( flags >= ATTR_FLAG_NONE && flags <= ATTR_FLAG_MAX );
REQUIRES( !( flags & ATTR_FLAG_INVALID ) );
/* Sanity-check the state */
ENSURES( attributeInfoPtr != NULL );
/* Check the field's validity */
status = checkAttributeField( *attributeListPtr, attributeInfoPtr,
fieldID, subFieldID, data, dataLength,
flags, &infoType, &newDataLength,
errorType );
if( cryptStatusError( status ) )
{
if( errorType != NULL && *errorType != CRYPT_ERRTYPE_NONE )
{
/* If we encountered an error that sets the error type, record
the locus */
*errorLocus = fieldID;
}
return( status );
}
ENSURES( infoType == CHECKATTR_INFO_ZEROLENGTH || \
( dataLength > 0 && dataLength < MAX_ATTRIBUTE_SIZE ) );
/* Find the location at which to insert this attribute field (this
assumes that the fieldIDs are defined in sorted order) */
for( insertPoint = *attributeListPtr, iterationCount = 0;
insertPoint != NULL && \
insertPoint->fieldID != CRYPT_ATTRIBUTE_NONE && \
insertPoint->fieldID <= fieldID && \
iterationCount < FAILSAFE_ITERATIONS_MAX;
iterationCount++ )
{
ENSURES( insertPoint->next == NULL || \
!isValidAttributeField( insertPoint->next ) || \
insertPoint->attributeID <= insertPoint->next->attributeID );
/* 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;
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MAX );
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 copy it into the storage in the element.
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 */
switch( infoType )
{
case CHECKATTR_INFO_NONE:
/* No special-case length handling */
storageSize = dataLength;
break;
case CHECKATTR_INFO_ZEROLENGTH:
/* Zero-length data, e.g. integer, boolean, DN placeholder */
storageSize = 0;
break;
case CHECKATTR_INFO_NEWLENGTH:
/* The length has changed due to data en/decoding, use the
en/decoded length for the storage size */
storageSize = newDataLength;
break;
default:
retIntError();
}
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. In the latter case the
amount of storage allocated is the space required by the
text form which is more than the BER/DER-encoded form but
we can't tell in advance how much we actually need to
allocate until we've performed the decoding */
if( ( ( BYTE * ) data )[ 0 ] == BER_OBJECT_IDENTIFIER )
{
memcpy( newElement->value, data, dataLength );
newElement->valueLength = dataLength;
}
else
{
status = textToOID( data, dataLength, newElement->value,
storageSize, &newElement->valueLength );
ENSURES( cryptStatusOK( status ) );
}
break;
case FIELDTYPE_DN:
/* When creating a new certificate this is a placeholder to
indicate that a DN structure is being instantiated. When
reading an encoded certificate 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:
ENSURES( dataLength > 0 && dataLength < MAX_ATTRIBUTE_SIZE );
memcpy( newElement->value, data, dataLength );
newElement->valueLength = dataLength;
break;
}
insertDoubleListElement( attributeListPtr, insertPoint, newElement );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Delete Attribute Data *
* *
****************************************************************************/
/* Delete an attribute/attribute field from a list of attributes, updating
the list cursor at the same time. This is a somewhat ugly kludge, it's
not really possible to do this cleanly since deleting attributes affects
the attribute cursor */
RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
int deleteAttributeField( INOUT ATTRIBUTE_LIST **attributeListPtr,
INOUT_OPT ATTRIBUTE_LIST **listCursorPtr,
INOUT ATTRIBUTE_LIST *listItem,
IN_OPT const void *dnCursor )
{
ATTRIBUTE_LIST *listPrevPtr = listItem->prev;
ATTRIBUTE_LIST *listNextPtr = listItem->next;
BOOLEAN deletedDN = FALSE;
assert( isWritePtr( attributeListPtr, sizeof( ATTRIBUTE_LIST * ) ) );
assert( isWritePtr( *attributeListPtr, sizeof( ATTRIBUTE_LIST ) ) );
assert( listCursorPtr == NULL || \
isWritePtr( listCursorPtr, sizeof( ATTRIBUTE_LIST * ) ) );
assert( isWritePtr( listItem, sizeof( ATTRIBUTE_LIST ) ) );
/* If we're about to delete the field that's pointed to by the attribute
cursor, advance the cursor to the next field. If there's no next
field, move it to the previous field. This behaviour is the most
logically consistent, it means that we can do things like deleting an
entire attribute list by repeatedly deleting a field */
if( listCursorPtr != NULL && *listCursorPtr == listItem )
*listCursorPtr = ( listNextPtr != NULL ) ? listNextPtr : listPrevPtr;
/* Remove the item from the list */
deleteDoubleListElement( attributeListPtr, listItem );
/* Clear all data in the item and free the memory */
if( listItem->fieldType == FIELDTYPE_DN )
{
/* If we've deleted the DN at the current cursor position, remember
this so that we can warn the caller */
if( dnCursor != NULL && dnCursor == &listItem->value )
deletedDN = TRUE;
deleteDN( ( void ** ) &listItem->value );
}
endVarStruct( listItem, ATTRIBUTE_LIST );
clFree( "deleteAttributeField", listItem );
/* If we deleted the DN at the current cursor position return a
special-case code to let the caller know */
return( deletedDN ? OK_SPECIAL : CRYPT_OK );
}
RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
int deleteAttribute( INOUT ATTRIBUTE_LIST **attributeListPtr,
INOUT_OPT ATTRIBUTE_LIST **listCursorPtr,
INOUT ATTRIBUTE_LIST *listItem,
IN_OPT const void *dnCursor )
{
CRYPT_ATTRIBUTE_TYPE attributeID;
ATTRIBUTE_LIST *attributeListCursor;
int iterationCount, status = CRYPT_OK;
assert( isWritePtr( attributeListPtr, sizeof( ATTRIBUTE_LIST * ) ) );
assert( isWritePtr( *attributeListPtr, sizeof( ATTRIBUTE_LIST ) ) );
assert( listCursorPtr == NULL || \
isWritePtr( listCursorPtr, sizeof( ATTRIBUTE_LIST * ) ) );
assert( isWritePtr( listItem, sizeof( ATTRIBUTE_LIST ) ) );
/* If it's a blob-type attribute, everything is contained in this one
list item so we only need to destroy that */
if( isBlobAttribute( listItem ) )
{
return( deleteAttributeField( attributeListPtr, listCursorPtr,
listItem, NULL ) );
}
/* If it's a field that denotes an entire (constructed) attribute it
won't have an entry in the list so we find the first field of the
constructed attribute that's present in the list and start deleting
from that point */
if( isCompleteAttribute( listItem ) )
{
for( attributeListCursor = *attributeListPtr;
attributeListCursor != NULL && \
attributeListCursor->attributeID != listItem->intValue;
attributeListCursor = attributeListCursor->next );
}
else
{
/* The list item is a field in the attribute, find the start of the
fields in this attribute */
attributeListCursor = findAttributeStart( listItem );
}
assert( isWritePtr( attributeListCursor, sizeof( ATTRIBUTE_LIST ) ) );
ENSURES( attributeListCursor != NULL );
attributeID = attributeListCursor->attributeID;
/* It's an item with multiple fields, destroy each field separately */
for( iterationCount = 0;
attributeListCursor != NULL && \
attributeListCursor->attributeID == attributeID && \
iterationCount < FAILSAFE_ITERATIONS_LARGE;
iterationCount++ )
{
ATTRIBUTE_LIST *itemToFree = attributeListCursor;
int localStatus;
attributeListCursor = attributeListCursor->next;
localStatus = deleteAttributeField( attributeListPtr, listCursorPtr,
itemToFree, dnCursor );
if( cryptStatusError( localStatus ) && status != OK_SPECIAL )
{
/* Remember the error code, giving priority to DN cursor-
modification notifications */
status = localStatus;
}
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
return( status );
}
/* Delete a complete set of attributes */
STDC_NONNULL_ARG( ( 1 ) ) \
void deleteAttributes( INOUT ATTRIBUTE_LIST **attributeListPtr )
{
ATTRIBUTE_LIST *attributeListCursor = *attributeListPtr;
int iterationCount;
assert( isWritePtr( attributeListPtr, sizeof( ATTRIBUTE_LIST * ) ) );
/* If the list was empty, return now */
if( attributeListCursor == NULL )
return;
/* Destroy any remaining list items */
for( iterationCount = 0;
attributeListCursor != NULL && \
iterationCount < FAILSAFE_ITERATIONS_MAX;
iterationCount++ )
{
ATTRIBUTE_LIST *itemToFree = attributeListCursor;
attributeListCursor = attributeListCursor->next;
deleteAttributeField( attributeListPtr, NULL, itemToFree, NULL );
}
ENSURES_V( iterationCount < FAILSAFE_ITERATIONS_MAX );
ENSURES_V( *attributeListPtr == NULL );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -