📄 dn.c
字号:
}
ENSURES_V( iterationCount < FAILSAFE_ITERATIONS_MED );
/* Mark the list as being empty */
*dnComponentListPtrPtr = NULL;
}
/* Get the value of a DN component */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 5 ) ) \
int getDNComponentValue( INOUT_PTR const void *dnComponentList,
IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE type,
OUT_BUFFER_OPT( valueMaxLength, \
valueLengthlength ) void *value,
IN_LENGTH_SHORT_Z const int valueMaxLength,
OUT_LENGTH_SHORT_Z int *valueLength )
{
const DN_COMPONENT *dnComponent;
assert( isReadPtr( dnComponentList, sizeof( DN_COMPONENT ) ) );
assert( ( value == NULL && valueMaxLength == 0 ) || \
( isWritePtr( value, valueMaxLength ) ) );
assert( isWritePtr( valueLength, sizeof( int ) ) );
REQUIRES( type > CRYPT_CERTINFO_FIRST && type < CRYPT_CERTINFO_LAST );
REQUIRES( ( value == NULL && valueMaxLength == 0 ) || \
( value != NULL && \
valueMaxLength >= 0 && \
valueMaxLength < MAX_INTLENGTH_SHORT ) );
/* Clear return values */
*valueLength = 0;
if( value != NULL )
memset( value, 0, min( 16, valueMaxLength ) );
dnComponent = findDNComponent( dnComponentList, type, NULL, 0 );
if( dnComponent == NULL )
return( CRYPT_ERROR_NOTFOUND );
*valueLength = dnComponent->valueLength;
if( value == NULL )
return( CRYPT_OK );
if( dnComponent->valueLength > valueMaxLength )
return( CRYPT_ERROR_OVERFLOW );
if( !isWritePtr( 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 */
CHECK_RETVAL_BOOL \
BOOLEAN compareDN( IN_OPT const void *dnComponentList1,
IN_OPT const void *dnComponentList2,
const BOOLEAN dn1substring )
{
DN_COMPONENT *dn1ptr, *dn2ptr;
int iterationCount;
assert( dnComponentList1 == NULL || \
isReadPtr( dnComponentList1, sizeof( DN_COMPONENT * ) ) );
assert( dnComponentList2 == NULL || \
isReadPtr( dnComponentList2, sizeof( DN_COMPONENT * ) ) );
/* Check each DN component for equality */
for( dn1ptr = ( DN_COMPONENT * ) dnComponentList1, \
dn2ptr = ( DN_COMPONENT * ) dnComponentList2,
iterationCount = 0;
dn1ptr != NULL && dn2ptr != NULL && \
iterationCount < FAILSAFE_ITERATIONS_MED;
dn1ptr = dn1ptr->next, dn2ptr = dn2ptr->next, iterationCount++ )
{
/* 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 in
their right mind 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 );
}
ENSURES_B( iterationCount < FAILSAFE_ITERATIONS_MED );
/* 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 */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int copyDN( OUT_PTR void **dnDest, IN_OPT const void *dnSrc )
{
const DN_COMPONENT *srcPtr;
DN_COMPONENT **dnDestPtrPtr = ( DN_COMPONENT ** ) dnDest;
DN_COMPONENT *destPtr = NULL;
int iterationCount;
assert( isWritePtr( dnDest, sizeof( DN_COMPONENT * ) ) );
assert( dnSrc == NULL || isReadPtr( dnSrc, sizeof( DN_COMPONENT * ) ) );
/* Clear return value */
*dnDest = NULL;
/* Copy each element in the source DN */
for( srcPtr = dnSrc, iterationCount= 0;
srcPtr != NULL && iterationCount < FAILSAFE_ITERATIONS_MED;
srcPtr = srcPtr->next, iterationCount++ )
{
DN_COMPONENT *newElement;
/* Allocate memory for the new element and copy over the
information. Since we're copying over the contents of an
existing DN_COMPONENT structure we have to zero the list links
after the copy */
if( ( newElement = ( DN_COMPONENT * ) \
clAlloc( "copyDN", \
sizeofVarStruct( srcPtr, DN_COMPONENT ) ) ) == NULL )
{
deleteDN( dnDest );
return( CRYPT_ERROR_MEMORY );
}
copyVarStruct( newElement, srcPtr, DN_COMPONENT );
newElement->prev = newElement->next = NULL;
/* Link it into the list */
insertDoubleListElement( dnDestPtrPtr, destPtr, newElement );
destPtr = newElement;
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
return( CRYPT_OK );
}
/* Check the validity of a DN. The check for the bottom of the DN (common
name) and top (country) are made configurable, DNs that act as filters
(e.g. path constraints) may not have the lower DN parts present and
certificate requests submitted to CAs that set the country themselves
may not have the country present */
CHECK_RETVAL STDC_NONNULL_ARG( ( 4, 5 ) ) \
int checkDN( IN_OPT const void *dnComponentList,
const BOOLEAN checkCN, const BOOLEAN checkC,
OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
CRYPT_ATTRIBUTE_TYPE *errorLocus,
OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
CRYPT_ERRTYPE_TYPE *errorType )
{
DN_COMPONENT *dnComponentListPtr;
BOOLEAN hasCountry = FALSE, hasCommonName = FALSE;
assert( dnComponentList == NULL || \
isReadPtr( dnComponentList, sizeof( DN_COMPONENT ) ) );
assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
/* Clear the return values */
*errorType = CRYPT_OK;
*errorLocus = CRYPT_ATTRIBUTE_NONE;
/* Perform a special-case check for a null DN */
if( dnComponentList == NULL )
return( CRYPT_ERROR_NOTINITED );
/* Make sure that certain critical components are present */
for( dnComponentListPtr = ( DN_COMPONENT * ) dnComponentList;
dnComponentListPtr != NULL;
dnComponentListPtr = dnComponentListPtr->next )
{
if( dnComponentListPtr->type == CRYPT_CERTINFO_COUNTRYNAME )
{
if( !checkCountryCode( ( char * ) dnComponentListPtr->value ) )
{
*errorType = CRYPT_ERRTYPE_ATTR_VALUE;
*errorLocus = CRYPT_CERTINFO_COUNTRYNAME;
return( CRYPT_ERROR_INVALID );
}
hasCountry = TRUE;
}
if( dnComponentListPtr->type == CRYPT_CERTINFO_COMMONNAME )
hasCommonName = TRUE;
}
if( ( checkC && !hasCountry ) || ( checkCN && !hasCommonName ) )
{
*errorType = CRYPT_ERRTYPE_ATTR_ABSENT;
*errorLocus = ( hasCountry ) ? CRYPT_CERTINFO_COMMONNAME : \
CRYPT_CERTINFO_COUNTRYNAME;
return( CRYPT_ERROR_NOTINITED );
}
return( CRYPT_OK );
}
/* Convert a DN component containing a PKCS #9 emailAddress or an RFC 1274
rfc822Mailbox into an rfc822Name */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int convertEmail( INOUT CERT_INFO *certInfoPtr,
/*?*/ void **dnComponentListPtrPtr,
IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE altNameType )
{
DN_COMPONENT *emailComponent;
SELECTION_STATE selectionState;
void *certDataPtr;
int status;
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
assert( isWritePtr( dnComponentListPtrPtr, sizeof( DN_COMPONENT ) ) );
assert( *dnComponentListPtrPtr == NULL || \
isWritePtr( *dnComponentListPtrPtr, sizeof( DN_COMPONENT ) ) );
REQUIRES( altNameType == CRYPT_CERTINFO_SUBJECTALTNAME || \
altNameType == CRYPT_CERTINFO_ISSUERALTNAME );
/* If there's no PKCS #9 email address present, try for an RFC 1274 one.
If that's not present either, exit */
if( *dnComponentListPtrPtr == NULL )
{
/* If there's an empty DN present, there's nothing to do */
return( CRYPT_OK );
}
emailComponent = findDNComponentByOID( *dnComponentListPtrPtr,
( const BYTE * ) "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01", 11 );
if( emailComponent == NULL )
{
emailComponent = findDNComponentByOID( *dnComponentListPtrPtr,
( const BYTE * ) "\x06\x09\x09\x92\x26\x89\x93\xF2\x2C\x01\x03", 11 );
if( emailComponent == NULL )
return( CRYPT_OK );
}
/* Try and add the email address component as an rfc822Name. Since this
changes the current GeneralName selection we have to be careful about
saving and restoring the state. In addition since we're changing the
internal state of an object which is technically in the high state we
have to temporarily disconnect the certificate data from the
certificate object to make it appear as a mutable object. This is an
unfortunate consequence of the fact that what we're doing is a
behind-the-scenes switch to move a certificate component from where it
is to where it really should be */
saveSelectionState( selectionState, certInfoPtr );
certDataPtr = certInfoPtr->certificate;
certInfoPtr->certificate = NULL;
status = addCertComponent( certInfoPtr, CRYPT_ATTRIBUTE_CURRENT,
&altNameType, 0 );
ENSURES( cryptStatusOK( status ) );
status = addCertComponent( certInfoPtr, CRYPT_CERTINFO_RFC822NAME,
emailComponent->value,
emailComponent->valueLength );
if( cryptStatusOK( status ) )
{
/* It was successfully copied over, delete the copy in the DN */
( void ) deleteComponent( ( DN_COMPONENT ** ) dnComponentListPtrPtr,
emailComponent );
}
else
{
/* If it's already present (which is somewhat odd since the presence
of an email address in the DN implies that the implementation
doesn't know about rfc822Name) we can't do anything about it */
if( status == CRYPT_ERROR_INITED )
status = CRYPT_OK;
else
{
/* Some certificates can contain garbage in the (supposed) email
address, normally the certificate would be rejected because
of this but if we're running in oblivious mode we can import
it successfully but then get an internal error code when we
try and perform this sideways add. To catch this we check
for invalid email addresses here and ignore an error status
if we get one */
if( cryptArgError( status ) )
status = CRYPT_OK;
}
}
certInfoPtr->certificate = certDataPtr;
restoreSelectionState( selectionState, certInfoPtr );
return( status );
}
/****************************************************************************
* *
* Read a DN *
* *
****************************************************************************/
/* Parse an AVA. This determines the AVA type and leaves the stream pointer
at the start of the data value */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 4 ) ) \
static int readAVA( INOUT STREAM *stream,
OUT_INT_Z int *type,
OUT_LENGTH_SHORT_Z int *length,
OUT_INT_Z int *stringTag )
{
BYTE oid[ MAX_OID_SIZE + 8 ];
int oidLength, tag, i, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( type, sizeof( int ) ) );
assert( isWritePtr( length, sizeof( int ) ) );
assert( isWritePtr( stringTag, sizeof( int ) ) );
/* Clear return values */
*type = 0;
*length = 0;
*stringTag = 0;
/* Read the start of the AVA and determine the type from the
AttributeType field. If we find something that we don't recognise we
indicate it as a non-component type that can be read or written but
not directly accessed by the user (although it can still be accessed
using the cursor functions) */
readSequence( stream, NULL );
status = readEncodedOID( stream, oid, MAX_OID_SIZE, &oidLength,
BER_OBJECT_IDENTIFIER );
if( cryptStatusError( status ) )
return( status );
for( i = 0; certInfoOIDs[ i ].oid != NULL && \
i < FAILSAFE_ARRAYSIZE( certInfoOIDs, DN_COMPONENT_INFO );
i++ )
{
const DN_COMPONENT_INFO *certInfoOID = &certInfoOIDs[ i ];
/* Perform a quick check of the OID. The majority of all DN OIDs
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -