📄 dn.c
字号:
{
newElement->prev = destPtr;
newElement->next = NULL;
destPtr->next = newElement;
destPtr = newElement;
}
}
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 which act as filters
(e.g. path constraints) may not have the lower DN parts present, and cert
requests submitted to CAs which set the country themselves may not have
the country present */
int checkDN( const void *dnComponentListHead,
const BOOLEAN checkCN, const BOOLEAN checkC,
CRYPT_ATTRIBUTE_TYPE *errorLocus,
CRYPT_ERRTYPE_TYPE *errorType )
{
DN_COMPONENT *dnComponentListPtr;
BOOLEAN hasCountry = TRUE, hasCommonName = FALSE;
/* Clear the return values */
*errorType = CRYPT_OK;
*errorLocus = CRYPT_ATTRIBUTE_NONE;
/* Make sure that certain critical components are present */
for( dnComponentListPtr = ( DN_COMPONENT * ) dnComponentListHead;
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 */
int convertEmail( CERT_INFO *certInfoPtr, void **dnListHead,
const CRYPT_ATTRIBUTE_TYPE altNameType )
{
DN_COMPONENT *emailComponent = findDNComponentByOID( *dnListHead,
( const BYTE * ) "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01" );
SELECTION_STATE selectionState;
void *certDataPtr;
int status;
/* If there's no PKCS #9 email address present, try for an RFC 1274 one.
If that's not present either, exit */
if( emailComponent == NULL )
{
emailComponent = findDNComponentByOID( *dnListHead,
( const BYTE * ) "\x06\x09\x09\x92\x26\x89\x93\xF2\x2C\x01\x03" );
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 cert data from the cert 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 cert 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 );
assert( 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 */
deleteComponent( dnListHead, 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 certs can contain garbage in the (supposed) email
address, normally the cert 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 */
static int readAVA( STREAM *stream, CRYPT_ATTRIBUTE_TYPE *type, int *length,
int *stringTag )
{
BYTE oid[ MAX_OID_SIZE ];
int oidLength, tag, i, status;
/* Clear return values */
*type = CRYPT_ATTRIBUTE_NONE;
*length = 0;
*stringTag = 0;
/* Read the start of the AVA and determine the type from the AttributeType
field. If we find something which we don't recognise, we indicate it
as a non-component type which 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 = readRawObject( stream, oid, &oidLength, MAX_OID_SIZE,
BER_OBJECT_IDENTIFIER );
if( cryptStatusError( status ) )
return( status );
for( i = 0; certInfoOIDs[ i ].oid != NULL; i++ )
if( !memcmp( certInfoOIDs[ i ].oid, oid, oidLength ) )
{
*type = ( certInfoOIDs[ i ].type != CRYPT_ATTRIBUTE_NONE ) ?
certInfoOIDs[ i ].type : i + DN_OID_OFFSET;
break;
}
if( *type == CRYPT_ATTRIBUTE_NONE )
{
/* If we don't recognise the component type, skip it */
readUniversal( stream );
return( OK_SPECIAL );
}
/* We've reached the data value, make sure it's in order */
tag = peekTag( stream );
if( tag == BER_BITSTRING )
{
/* Bitstrings are used for uniqueIdentifiers, however these usually
encapsulate something else so we dig one level deeper to find the
encapsulated string */
readBitStringHole( stream, NULL, DEFAULT_TAG );
tag = peekTag( stream );
}
*stringTag = tag;
return( readGenericHole( stream, length, tag ) );
}
/* Read an RDN component */
static int readRDNcomponent( STREAM *stream, void **dnComponentListHead,
const int rdnDataLeft )
{
CRYPT_ATTRIBUTE_TYPE type;
BYTE stringBuffer[ MAX_ATTRIBUTE_SIZE ], *value;
const int rdnStart = stell( stream );
int valueLength, stringTag;
int flags = DN_FLAG_NOCHECK, status;
/* Read the type information for this AVA */
status = readAVA( stream, &type, &valueLength, &stringTag );
if( cryptStatusError( status ) )
return( status );
value = sMemBufPtr( stream );
if( valueLength <= 0 )
/* Skip broken AVAs with zero-length strings */
return( CRYPT_OK );
status = sSkip( stream, valueLength );
if( cryptStatusError( status ) )
return( status );
/* If there's room for another AVA, mark this one as being continued. The
+10 is the minimum length for an AVA: SEQ { OID, value } (2-bytes SEQ +
5-bytes OID + 2-bytes tag + len + 1 byte min-length data). We don't do
a simple =/!= check to get around incorrectly encoded lengths */
if( rdnDataLeft >= ( stell( stream ) - rdnStart ) + 10 )
flags |= DN_FLAG_CONTINUED;
/* Convert the string into the local character set */
status = copyFromAsn1String( stringBuffer, &valueLength,
MAX_ATTRIBUTE_SIZE, value, valueLength,
stringTag );
if( cryptStatusError( status ) )
return( status );
/* Add the DN component to the DN. If we hit a non-memory related error
we turn it into a generic CRYPT_ERROR_BADDATA error, since the other
codes are somewhat too specific for this case (e.g. CRYPT_ERROR_INITED
or an arg error isn't too useful for the caller) */
status = insertDNstring( dnComponentListHead, type, stringBuffer,
valueLength, flags, NULL );
return( ( cryptStatusError( status ) && status != CRYPT_ERROR_MEMORY ) ? \
CRYPT_ERROR_BADDATA : status );
}
/* Read a DN */
int readDN( STREAM *stream, void **dnComponentListHead )
{
int length, status;
status = readSequence( stream, &length );
if( cryptStatusError( status ) )
return( status );
while( length > 0 )
{
const int startPos = stell( stream );
int rdnLength;
/* Read the start of the RDN */
status = readSet( stream, &rdnLength );
if( cryptStatusError( status ) )
return( status );
/* Read each RDN component */
while( rdnLength > 0 )
{
const int rdnStart = stell( stream );
status = readRDNcomponent( stream, dnComponentListHead,
rdnLength );
if( cryptStatusError( status ) && status != OK_SPECIAL )
return( status );
rdnLength -= stell( stream ) - rdnStart;
}
if( rdnLength < 0 )
return( CRYPT_ERROR_BADDATA );
length -= stell( stream ) - startPos;
}
if( length < 0 )
return( CRYPT_ERROR_BADDATA );
return( sGetStatus( stream ) );
}
/****************************************************************************
* *
* Write a DN *
* *
****************************************************************************/
/* Perform the pre-encoding processing for a DN */
static int preEncodeDN( DN_COMPONENT *dnComponentPtr )
{
int size = 0;
if( dnComponentPtr == NULL )
return( 0 );
assert( isReadPtr( dnComponentPtr, sizeof( DN_COMPONENT ) ) );
/* If we're being fed an entry in the middle of a DN, move back to the
start */
while( dnComponentPtr->prev != NULL )
dnComponentPtr = dnComponentPtr->prev;
/* Walk down the DN pre-encoding each AVA */
while( dnComponentPtr != NULL )
{
DN_COMPONENT *rdnStartPtr = dnComponentPtr;
BOOLEAN isContinued;
/* If this component has already had pre-encoding processing
applied, there's no need to do it again */
if( dnComponentPtr->flags & DN_FLAG_PREENCODED )
{
if( dnComponentPtr->encodedRDNdataSize > 0 )
size += ( int ) sizeofObject( dnComponentPtr->encodedRDNdataSize );
dnComponentPtr = dnComponentPtr->next;
continue;
}
/* Calculate the size of every AVA in this RDN */
do
{
const DN_COMPONENT_INFO *dnComponentInfo = dnComponentPtr->typeInfo;
int dnStringLength, status;
status = getAsn1StringInfo( dnComponentPtr->value,
dnComponentPtr->valueLength,
&dnComponentPtr->valueStringType,
&dnComponentPtr->encodedStringType,
&dnStringLength );
if( cryptStatusError( status ) )
return( status );
dnComponentPtr->encodedAVAdataSize = ( int ) \
sizeofOID( dnComponentInfo->oid ) + \
sizeofObject( dnStringLength );
dnComponentPtr->encodedRDNdataSize = 0;
dnComponentPtr->flags |= DN_FLAG_PREENCODED;
rdnStartPtr->encodedRDNdataSize += ( int ) \
sizeofObject( dnComponentPtr->encodedAVAdataSize );
isContinued = dnComponentPtr->flags & DN_FLAG_CONTINUED;
dnComponentPtr = dnComponentPtr->next;
}
while( isContinued && dnComponentPtr != NULL );
/* Calculate the overall size of the RDN */
size += ( int ) sizeofObject( rdnStartPtr->encodedRDNdataSize );
}
return( size );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -