📄 certext.c
字号:
/* Moving by field or component is relatively simple. For fields we move
backwards or forwards until we either run out of fields or the next
field belongs to a different attribute. For components we move
similarly, except that we stop when we reach a field whose attribute
type, field type, and subfield type don't match the current one */
if( certInfoType == CRYPT_CERTINFO_CURRENT_FIELD )
{
const CRYPT_ATTRIBUTE_TYPE attributeID = ( *currentCursor )->attributeID;
if( position == CRYPT_CURSOR_FIRST || position == CRYPT_CURSOR_PREVIOUS )
while( count-- && newCursor->prev != NULL && \
newCursor->prev->attributeID == attributeID )
newCursor = newCursor->prev;
else
while( count-- && newCursor->next != NULL && \
newCursor->next->attributeID == attributeID )
newCursor = newCursor->next;
if( !absMove && *currentCursor == newCursor )
return( CRYPT_ERROR_NOTFOUND );
*currentCursor = ( ATTRIBUTE_LIST * ) newCursor;
return( CRYPT_OK );
}
if( certInfoType == CRYPT_CERTINFO_CURRENT_COMPONENT )
{
const CRYPT_ATTRIBUTE_TYPE attributeID = ( *currentCursor )->attributeID;
const CRYPT_ATTRIBUTE_TYPE fieldID = ( *currentCursor )->fieldID;
const CRYPT_ATTRIBUTE_TYPE subFieldID = ( *currentCursor )->subFieldID;
if( position == CRYPT_CURSOR_FIRST || position == CRYPT_CURSOR_PREVIOUS )
while( count-- && newCursor->prev != NULL && \
newCursor->prev->attributeID == attributeID && \
newCursor->prev->fieldID == fieldID && \
newCursor->prev->subFieldID == subFieldID )
newCursor = newCursor->prev;
else
while( count-- && newCursor->next != NULL && \
newCursor->next->attributeID == attributeID && \
newCursor->next->fieldID == fieldID && \
newCursor->next->subFieldID == subFieldID )
newCursor = newCursor->next;
if( !absMove && *currentCursor == newCursor )
return( CRYPT_ERROR_NOTFOUND );
*currentCursor = ( ATTRIBUTE_LIST * ) newCursor;
return( CRYPT_OK );
}
/* Moving by attribute is a bit more complex. First we find the start or
end of the current attribute. Then we move to the start of the
previous (via findAttributeStart())/start of the next (via the 'next'
pointer) attribute beyond that. This has the effect of moving us from
anywhere in the current attribute to the start of the preceding or
following attribute. Finally, we repeat this as required */
while( count-- && newCursor != NULL )
{
lastCursor = newCursor;
if( position == CRYPT_CURSOR_FIRST || position == CRYPT_CURSOR_PREVIOUS )
newCursor = findAttributeStart( findAttributeStart( newCursor )->prev );
else
newCursor = findAttributeEnd( newCursor )->next;
}
assert( lastCursor != NULL ); /* We went through loop at least once */
/* If the new cursor is NULL, we've reached the start or end of the
attribute list */
if( newCursor == NULL )
{
/* Move to the start of the first or last attribute we got to before
we ran out of attributes to make sure that we don't fall off the
start/end of the list */
*currentCursor = findAttributeStart( lastCursor );
/* If it's an absolute move we've reached our destination, otherwise
there's nowhere left to move to */
return( absMove ? CRYPT_OK : CRYPT_ERROR_NOTFOUND );
}
/* We've found what we were looking for */
*currentCursor = ( ATTRIBUTE_LIST * ) newCursor;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Misc. Attribute Routines *
* *
****************************************************************************/
/* Fix up certificate attributes, mapping from incorrect values to standards-
compliant ones */
int fixAttributes( CERT_INFO *certInfoPtr )
{
ATTRIBUTE_LIST *attributeListPtr;
int complianceLevel, status;
/* Try and locate email addresses wherever they might be stashed and move
them to the cert altNames */
status = convertEmail( certInfoPtr, &certInfoPtr->subjectName,
CRYPT_CERTINFO_SUBJECTALTNAME );
if( cryptStatusOK( status ) )
status = convertEmail( certInfoPtr, &certInfoPtr->issuerName,
CRYPT_CERTINFO_ISSUERALTNAME );
if( cryptStatusError( status ) )
return( status );
/* If we're running at a compliance level of
CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL or above, don't try and fiddle any
dubious attributes */
status = krnlSendMessage( certInfoPtr->ownerHandle,
IMESSAGE_GETATTRIBUTE, &complianceLevel,
CRYPT_OPTION_CERT_COMPLIANCELEVEL );
if( cryptStatusError( status ) )
return( status );
if( complianceLevel >= CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL )
return( CRYPT_OK );
/* If the only key usage info present is the Netscape one, convert it
into the X.509 equivalent */
if( findAttributeField( certInfoPtr->attributes, CRYPT_CERTINFO_KEYUSAGE,
CRYPT_ATTRIBUTE_NONE ) == NULL && \
( attributeListPtr = findAttributeField( certInfoPtr->attributes,
CRYPT_CERTINFO_NS_CERTTYPE,
CRYPT_ATTRIBUTE_NONE ) ) != NULL )
{
int keyUsage = 0;
/* There's a Netscape cert usage present but no X.509 one, map the
Netscape usage to the X.509 one */
if( attributeListPtr->intValue & CRYPT_NS_CERTTYPE_SSLCLIENT )
keyUsage |= CRYPT_KEYUSAGE_DIGITALSIGNATURE;
if( attributeListPtr->intValue & CRYPT_NS_CERTTYPE_SSLSERVER )
keyUsage |= CRYPT_KEYUSAGE_KEYENCIPHERMENT;
if( attributeListPtr->intValue & CRYPT_NS_CERTTYPE_SMIME )
{
keyUsage |= CRYPT_KEYUSAGE_DIGITALSIGNATURE;
if( certInfoPtr->iPubkeyContext != CRYPT_ERROR )
{
int cryptAlgo;
krnlSendMessage( certInfoPtr->iPubkeyContext,
IMESSAGE_GETATTRIBUTE, &cryptAlgo,
CRYPT_CTXINFO_ALGO );
if( isCryptAlgo( cryptAlgo ) )
keyUsage |= CRYPT_KEYUSAGE_KEYENCIPHERMENT;
}
}
if( attributeListPtr->intValue & ( CRYPT_NS_CERTTYPE_SSLCA | \
CRYPT_NS_CERTTYPE_SMIMECA | \
CRYPT_NS_CERTTYPE_OBJECTSIGNINGCA ) )
keyUsage |= CRYPT_KEYUSAGE_KEYCERTSIGN | CRYPT_KEYUSAGE_CRLSIGN;
status = addAttributeField( &certInfoPtr->attributes,
CRYPT_CERTINFO_KEYUSAGE, CRYPT_ATTRIBUTE_NONE,
&keyUsage, CRYPT_UNUSED, ATTR_FLAG_NONE,
&certInfoPtr->errorLocus, &certInfoPtr->errorType );
if( cryptStatusError( status ) )
return( status );
}
return( CRYPT_OK );
}
/****************************************************************************
* *
* Attribute Management Routines *
* *
****************************************************************************/
/* Add a blob-type attribute to a list of attributes */
int addAttribute( const ATTRIBUTE_TYPE attributeType,
ATTRIBUTE_LIST **listHeadPtr, const BYTE *oid,
const BOOLEAN criticalFlag, const void *data,
const int dataLength, const int flags )
{
ATTRIBUTE_LIST *newElement, *insertPoint = NULL;
const int storageSize = dataLength + sizeofOID( oid );
assert( isWritePtr( listHeadPtr, ATTRIBUTE_LIST * ) );
assert( isReadPtr( oid, 3 ) );
assert( criticalFlag == TRUE || criticalFlag == FALSE );
assert( !checkBadPtrRead( data, dataLength ) );
assert( dataLength > 0 && dataLength <= MAX_ATTRIBUTE_SIZE );
assert( flags == ATTR_FLAG_NONE || flags == ATTR_FLAG_BLOB );
/* 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 ) != 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 ) == sizeofOID( oid ) && \
!memcmp( insertPoint->oid, oid, sizeofOID( oid ) ) )
return( CRYPT_ERROR_INITED );
prevElement = insertPoint;
}
insertPoint = prevElement;
}
/* Allocate memory for the new element and copy the information across */
if( ( newElement = ( ATTRIBUTE_LIST * ) \
clAlloc( "addAttribute", sizeof( ATTRIBUTE_LIST ) + \
storageSize ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
initVarStruct( newElement, ATTRIBUTE_LIST, storageSize );
newElement->oid = newElement->storage + dataLength;
memcpy( newElement->oid, oid, sizeofOID( oid ) );
newElement->flags = criticalFlag ? ATTR_FLAG_CRITICAL : ATTR_FLAG_NONE;
memcpy( newElement->value, data, dataLength );
newElement->valueLength = dataLength;
insertDoubleListElements( listHeadPtr, insertPoint, newElement, newElement );
return( CRYPT_OK );
}
/* Check the validity of an attribute field */
static int checkAttributeField( const ATTRIBUTE_LIST *attributeListPtr,
const ATTRIBUTE_INFO *attributeInfoPtr,
const CRYPT_ATTRIBUTE_TYPE fieldID,
const CRYPT_ATTRIBUTE_TYPE subFieldID,
const void *data, const int dataLength,
const int flags,
CRYPT_ERRTYPE_TYPE *errorType )
{
ATTRIBUTE_LIST *attributeListSearchPtr;
assert( isReadPtr( attributeInfoPtr, ATTRIBUTE_INFO ) );
assert( dataLength == CRYPT_UNUSED || \
( dataLength > 0 && dataLength <= MAX_ATTRIBUTE_SIZE ) );
assert( dataLength == CRYPT_UNUSED || \
!checkBadPtrRead( data, dataLength ) );
assert( !( flags & ATTR_FLAG_INVALID ) );
/* 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 );
attributeListSearchPtr = findAttributeField( attributeListPtr, fieldID,
subFieldID );
if( attributeListSearchPtr != 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 */
assert( dataLength == CRYPT_UNUSED );
if( *( ( int * ) data ) != CRYPT_UNUSED )
return( CRYPT_ARGERROR_NUM1 );
return( CRYPT_OK );
case FIELDTYPE_DN:
/* It's a special-case field used as a placeholder when creating
a new cert to indicate that a DN structure is being
instantiated. When reading an encoded cert, this is the
decoded DN structure */
assert( dataLength == CRYPT_UNUSED );
return( CRYPT_OK );
case BER_OBJECT_IDENTIFIER:
{
const BYTE *oidPtr = data;
BYTE binaryOID[ MAX_OID_SIZE ];
/* If it's a BER/DER-encoded OID, make sure that it's valid
ASN.1 */
if( oidPtr[ 0 ] == BER_OBJECT_IDENTIFIER )
{
if( oidPtr[ 1 ] == dataLength - 2 )
return( CRYPT_OK );
}
else
/* It's a text OID, check the syntax and make sure that the
length is valid */
if( textToOID( data, dataLength, binaryOID ) )
return( CRYPT_OK );
if( errorType != NULL )
*errorType = CRYPT_ERRTYPE_ATTR_VALUE;
return( CRYPT_ARGERROR_STR1 );
}
case BER_BOOLEAN:
assert( dataLength == CRYPT_UNUSED );
/* BOOLEAN data is accepted as zero/nonzero so it's always
valid, however we let the caller know via an alternative
return code that this is non-string data */
return( OK_SPECIAL );
case BER_INTEGER:
case BER_ENUMERATED:
case BER_BITSTRING:
case BER_NULL:
case FIELDTYPE_CHOICE:
{
int value = *( ( int * ) data );
/* Check that the data size and 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 */
return( OK_SPECIAL );
}
}
/* It's some sort of string value, perform a general type 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 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -