📄 ext_add.c
字号:
/****************************************************************************
* *
* Certificate Attribute Add/Delete Routines *
* Copyright Peter Gutmann 1996-2007 *
* *
****************************************************************************/
#if defined( INC_ALL )
#include "cert.h"
#include "certattr.h"
#include "asn1.h"
#else
#include "cert/cert.h"
#include "cert/certattr.h"
#include "misc/asn1.h"
#endif /* Compiler-specific includes */
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Check the validity of an attribute field */
typedef enum {
CHECKATTR_INFO_NONE, /* No special return info */
CHECKATTR_INFO_ZEROLENGTH, /* Zero-length data, e.g.int, bool, DN placeholder */
CHECKATTR_INFO_NEWLENGTH, /* Data length change, value in newDataLength */
CHECKATTR_INFO_LAST /* Last possible return info type */
} CHECKATTR_INFO_TYPE;
CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 2, 8, 9, 10 ) ) \
static int checkAttributeField( IN_OPT const ATTRIBUTE_LIST *attributeListPtr,
const ATTRIBUTE_INFO *attributeInfoPtr,
IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE fieldID,
IN_ATTRIBUTE_OPT \
const CRYPT_ATTRIBUTE_TYPE subFieldID,
/*?*/ const void *data,
/*?*/ const int dataLength,
IN_FLAGS( ATTR ) const int flags,
OUT_ENUM_OPT( CHECKATTR_INFO ) \
CHECKATTR_INFO_TYPE *infoType,
OUT_LENGTH_SHORT_Z int *newDataLength,
OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
CRYPT_ERRTYPE_TYPE *errorType )
{
int status;
assert( attributeListPtr == NULL || \
isReadPtr( attributeListPtr, sizeof( ATTRIBUTE_LIST ) ) );
assert( isReadPtr( attributeInfoPtr, sizeof( ATTRIBUTE_INFO ) ) );
assert( dataLength == CRYPT_UNUSED || isReadPtr( data, dataLength ) );
assert( isWritePtr( infoType, sizeof( CHECKATTR_INFO_TYPE ) ) );
assert( isWritePtr( newDataLength, sizeof( int ) ) );
assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
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_NONE | ATTR_FLAG_BLOB_PAYLOAD | ATTR_FLAG_CRITICAL | ATTR_FLAG_MULTIVALUED ) ) == 0 );
REQUIRES( flags >= ATTR_FLAG_NONE && flags <= ATTR_FLAG_MAX );
REQUIRES( !( flags & ATTR_FLAG_INVALID ) );
/* Clear return values */
*infoType = CHECKATTR_INFO_NONE;
*newDataLength = 0;
/* Make sure that a valid field has been specified and that this field
isn't already present as a non-default entry unless it's a field for
which multiple values are allowed */
if( attributeInfoPtr == NULL )
return( CRYPT_ARGERROR_VALUE );
if( attributeListPtr != NULL && \
findAttributeField( attributeListPtr, fieldID, subFieldID ) != NULL )
{
/* If it's not multivalued, we can't have any duplicate fields */
if( !( ( attributeInfoPtr->flags & FL_MULTIVALUED ) || \
( flags & ATTR_FLAG_MULTIVALUED ) ) )
{
if( errorType != NULL )
*errorType = CRYPT_ERRTYPE_ATTR_PRESENT;
return( CRYPT_ERROR_INITED );
}
}
/* If it's a blob field, don't do any type checking. This is a special
case that differs from FIELDTYPE_BLOB in that it corresponds to an
ASN.1 value that's mis-encoded by one or more implementations, so we
have to accept absolutely anything at this point */
if( flags & ATTR_FLAG_BLOB )
return( CRYPT_OK );
switch( attributeInfoPtr->fieldType )
{
case FIELDTYPE_IDENTIFIER:
/* It's an identifier, make sure that all parameters are correct */
ENSURES( dataLength == CRYPT_UNUSED );
if( *( ( int * ) data ) != CRYPT_UNUSED )
return( CRYPT_ARGERROR_NUM1 );
/* Tell the caller that this is a special-case entry with
zero-length data */
*infoType = CHECKATTR_INFO_ZEROLENGTH;
return( CRYPT_OK );
case FIELDTYPE_DN:
/* When creating a new certificate this is a special-case field
that's used as a placeholder to indicate that a DN structure
is being instantiated. When reading an encoded certificate
this is the decoded DN structure */
ENSURES( dataLength == CRYPT_UNUSED );
/* Tell the caller that this is a special-case entry with
zero-length data */
*infoType = CHECKATTR_INFO_ZEROLENGTH;
return( CRYPT_OK );
case BER_OBJECT_IDENTIFIER:
{
const BYTE *oidPtr = data;
BYTE binaryOID[ MAX_OID_SIZE + 8 ];
/* If it's a BER/DER-encoded OID, make sure that it's valid
ASN.1 */
if( oidPtr[ 0 ] == BER_OBJECT_IDENTIFIER )
{
if( dataLength >= 3 && sizeofOID( oidPtr ) == dataLength )
return( CRYPT_OK );
}
else
{
int length;
/* It's a text OID, check the syntax and make sure that the
length is valid */
status = textToOID( data, dataLength, binaryOID,
MAX_OID_SIZE, &length );
if( cryptStatusOK( status ) )
{
/* The binary form of the OID differs in length from the
string form, tell the caller that the data length has
changed */
*infoType = CHECKATTR_INFO_NEWLENGTH;
*newDataLength = length;
return( CRYPT_OK );
}
}
if( errorType != NULL )
*errorType = CRYPT_ERRTYPE_ATTR_VALUE;
return( CRYPT_ARGERROR_STR1 );
}
case BER_BOOLEAN:
ENSURES( dataLength == CRYPT_UNUSED );
/* BOOLEAN data is accepted as zero/nonzero so it's always
valid, however we let the caller know that this is non-string
data with no storage requirements */
*infoType = CHECKATTR_INFO_ZEROLENGTH;
return( CRYPT_OK );
case BER_INTEGER:
case BER_ENUMERATED:
case BER_BITSTRING:
case BER_NULL:
case FIELDTYPE_CHOICE:
{
int value = *( ( int * ) data );
/* Check that the range is valid */
if( value < attributeInfoPtr->lowRange || \
value > attributeInfoPtr->highRange )
{
if( errorType != NULL )
*errorType = CRYPT_ERRTYPE_ATTR_VALUE;
return( CRYPT_ARGERROR_NUM1 );
}
/* Let the caller know that this is non-string data with no
storage requirements */
*infoType = CHECKATTR_INFO_ZEROLENGTH;
return( CRYPT_OK );
}
}
/* It's some sort of string value, perform a general data size check */
if( dataLength < attributeInfoPtr->lowRange || \
dataLength > attributeInfoPtr->highRange )
{
if( errorType != NULL )
*errorType = CRYPT_ERRTYPE_ATTR_SIZE;
return( CRYPT_ARGERROR_NUM1 );
}
/* If we're not checking the payload in order to handle CAs who stuff
any old rubbish into the fields exit now unless it's a blob field,
for which we need to find at least valid ASN.1 data */
if( ( flags & ATTR_FLAG_BLOB_PAYLOAD ) && \
( attributeInfoPtr->fieldType != FIELDTYPE_BLOB ) )
return( CRYPT_OK );
switch( attributeInfoPtr->fieldType )
{
case FIELDTYPE_BLOB:
/* It's a blob field, make sure that it's a valid ASN.1 object */
status = checkObjectEncoding( data, dataLength );
if( cryptStatusError( status ) )
{
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 that 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 that 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 Attribute Data *
* *
****************************************************************************/
/* Add a blob-type attribute to a list of attributes */
CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 3, 6 ) ) \
int addAttribute( IN_ENUM( ATTRIBUTE ) const ATTRIBUTE_TYPE attributeType,
/*?*/ ATTRIBUTE_LIST **listHeadPtr,
IN_BUFFER( oidLength ) const BYTE *oid,
IN_RANGE( MIN_OID_SIZE, MAX_OID_SIZE ) const int oidLength,
const BOOLEAN critical,
IN_BUFFER( dataLength ) const void *data,
IN_LENGTH_SHORT const int dataLength,
IN_FLAGS_Z( ATTR ) const int flags )
{
ATTRIBUTE_LIST *newElement, *insertPoint = NULL;
assert( isWritePtr( listHeadPtr, sizeof( ATTRIBUTE_LIST * ) ) );
assert( isReadPtr( oid, oidLength ) );
assert( isReadPtr( data, dataLength ) );
assert( ( flags & ( ATTR_FLAG_IGNORED | ATTR_FLAG_BLOB ) ) || \
!cryptStatusError( checkObjectEncoding( data, dataLength ) ) );
REQUIRES( attributeType == ATTRIBUTE_CERTIFICATE || \
attributeType == ATTRIBUTE_CMS );
REQUIRES( oidLength >= MIN_OID_SIZE && oidLength <= MAX_OID_SIZE && \
oidLength == sizeofOID( oid ) );
REQUIRES( data != NULL && \
dataLength > 0 && dataLength <= MAX_ATTRIBUTE_SIZE );
assert( ( flags & ~( ATTR_FLAG_NONE | ATTR_FLAG_IGNORED | ATTR_FLAG_BLOB | ATTR_FLAG_MULTIVALUED ) ) == 0 );
REQUIRES( flags == ATTR_FLAG_NONE || flags == ATTR_FLAG_BLOB || \
flags == ( ATTR_FLAG_BLOB | ATTR_FLAG_IGNORED ) );
/* If this attribute type is already handled as a non-blob attribute,
don't allow it to be added as a blob as well. This avoids problems
with the same attribute being added twice, once as a blob and once as
a non-blob. In addition it forces the caller to use the (recommended)
normal attribute handling mechanism, which allows for proper type
checking */
if( !( flags & ATTR_FLAG_BLOB ) && \
oidToAttribute( attributeType, oid, oidLength ) != NULL )
return( CRYPT_ERROR_PERMISSION );
/* Find the correct place in the list to insert the new element */
if( *listHeadPtr != NULL )
{
ATTRIBUTE_LIST *prevElement = NULL;
for( insertPoint = *listHeadPtr; insertPoint != NULL;
insertPoint = insertPoint->next )
{
/* Make sure that this blob attribute isn't already present */
if( isBlobAttribute( insertPoint ) && \
sizeofOID( insertPoint->oid ) == oidLength && \
!memcmp( insertPoint->oid, oid, oidLength ) )
return( CRYPT_ERROR_INITED );
prevElement = insertPoint;
}
insertPoint = prevElement;
}
/* Allocate memory for the new element and copy the information across.
The data is stored in storage ... storage + dataLength, the OID in
storage + dataLength ... storage + dataLength + oidLength */
if( ( newElement = ( ATTRIBUTE_LIST * ) \
clAlloc( "addAttribute", sizeof( ATTRIBUTE_LIST ) + \
dataLength + oidLength ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
initVarStruct( newElement, ATTRIBUTE_LIST, dataLength + oidLength );
newElement->oid = newElement->storage + dataLength;
memcpy( newElement->oid, oid, oidLength );
newElement->flags = ( flags & ATTR_FLAG_IGNORED ) | \
( critical ? ATTR_FLAG_CRITICAL : ATTR_FLAG_NONE );
memcpy( newElement->value, data, dataLength );
newElement->valueLength = dataLength;
insertDoubleListElements( listHeadPtr, insertPoint, newElement, newElement );
return( CRYPT_OK );
}
/* Add an attribute field to a list of attributes at the appropriate
location */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 7, 8 ) ) \
int addAttributeField( /*?*/ ATTRIBUTE_LIST **attributeListPtr,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -