📄 dn.c
字号:
are of the form (2 5 4 n), encoded as 0x06 0x03 0x55 0x04 0xnn,
so we compare the byte at offset 4 for the quick-reject match
before we go for the full OID match */
if( certInfoOID->oid[ 4 ] == oid[ 4 ] && \
!memcmp( certInfoOID->oid, oid, oidLength ) )
{
*type = certInfoOID->type;
break;
}
}
ENSURES( i < FAILSAFE_ARRAYSIZE( certInfoOIDs, DN_COMPONENT_INFO ) );
if( certInfoOIDs[ i ].oid == NULL )
{
/* If we don't recognise the component type, skip it */
readUniversal( stream );
return( OK_SPECIAL );
}
/* We've reached the data value, make sure that it's in order. When we
read the wrapper around the string type we have to allow a minimum
length of zero instead of one because of broken AVAs with zero-length
strings */
tag = peekTag( stream );
if( cryptStatusError( tag ) )
return( tag );
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, 2, DEFAULT_TAG );
tag = peekTag( stream );
if( cryptStatusError( tag ) )
return( tag );
}
*stringTag = tag;
return( readGenericHole( stream, length, 0, tag ) );
}
/* Read an RDN component */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readRDNcomponent( INOUT STREAM *stream,
/*?*/ DN_COMPONENT **dnComponentListPtrPtr,
IN_LENGTH_SHORT const int rdnDataLeft )
{
CRYPT_ERRTYPE_TYPE dummy;
BYTE stringBuffer[ MAX_ATTRIBUTE_SIZE + 8 ];
void *value;
const int rdnStart = stell( stream );
int type, valueLength, stringTag;
int flags = DN_FLAG_NOCHECK, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( dnComponentListPtrPtr, sizeof( DN_COMPONENT * ) ) );
REQUIRES( rdnDataLeft > 0 && rdnDataLeft < MAX_INTLENGTH_SHORT );
/* Read the type information for this AVA */
status = readAVA( stream, &type, &valueLength, &stringTag );
if( cryptStatusError( status ) )
return( status );
if( valueLength <= 0 )
{
/* Skip broken AVAs with zero-length strings */
return( CRYPT_OK );
}
status = sMemGetDataBlock( stream, &value, valueLength );
if( cryptStatusOK( status ) )
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, MAX_ATTRIBUTE_SIZE,
&valueLength, 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( ( DN_COMPONENT ** ) dnComponentListPtrPtr, type,
stringBuffer, valueLength, flags, &dummy );
return( ( cryptStatusError( status ) && status != CRYPT_ERROR_MEMORY ) ? \
CRYPT_ERROR_BADDATA : status );
}
/* Read a DN */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int readDN( INOUT STREAM *stream,
INOUT_PTR void **dnComponentListPtrPtr )
{
int length, iterationCount, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( dnComponentListPtrPtr, sizeof( DN_COMPONENT * ) ) );
status = readSequence( stream, &length );
if( cryptStatusError( status ) )
return( status );
for( iterationCount = 0;
length > 0 && iterationCount < FAILSAFE_ITERATIONS_MED;
iterationCount++ )
{
const int startPos = stell( stream );
int rdnLength, innerIterationCount;
/* Read the start of the RDN */
status = readSet( stream, &rdnLength );
if( cryptStatusError( status ) )
return( status );
/* Read each RDN component */
for( innerIterationCount = 0;
rdnLength > 0 && innerIterationCount < FAILSAFE_ITERATIONS_MED;
innerIterationCount++ )
{
const int rdnStart = stell( stream );
status = readRDNcomponent( stream,
( DN_COMPONENT ** ) dnComponentListPtrPtr,
rdnLength );
if( cryptStatusError( status ) && status != OK_SPECIAL )
return( status );
rdnLength -= stell( stream ) - rdnStart;
}
if( rdnLength < 0 || \
innerIterationCount >= FAILSAFE_ITERATIONS_MED )
return( CRYPT_ERROR_BADDATA );
length -= stell( stream ) - startPos;
}
if( length < 0 || iterationCount >= FAILSAFE_ITERATIONS_MED )
return( CRYPT_ERROR_BADDATA );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Write a DN *
* *
****************************************************************************/
/* Perform the pre-encoding processing for a DN */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int preEncodeDN( INOUT DN_COMPONENT *dnComponentPtr,
OUT_LENGTH_SHORT_Z int *length )
{
int size = 0, iterationCount;
assert( isWritePtr( dnComponentPtr, sizeof( DN_COMPONENT ) ) );
assert( isWritePtr( length, sizeof( int ) ) );
/* Clear return value */
*length = 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 */
for( iterationCount = 0;
dnComponentPtr->prev != NULL && \
iterationCount < FAILSAFE_ITERATIONS_MED;
dnComponentPtr = dnComponentPtr->prev, iterationCount++ );
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
/* Walk down the DN pre-encoding each AVA */
for( iterationCount = 0;
dnComponentPtr != NULL && iterationCount < FAILSAFE_ITERATIONS_MED;
iterationCount++ )
{
DN_COMPONENT *rdnStartPtr = dnComponentPtr;
BOOLEAN isContinued;
int innerIterationCount;
/* 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 */
for( isContinued = TRUE, innerIterationCount = 0;
isContinued && dnComponentPtr != NULL && \
innerIterationCount < FAILSAFE_ITERATIONS_MED;
dnComponentPtr = dnComponentPtr->next, innerIterationCount++ )
{
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 ) ? \
TRUE : FALSE;
}
ENSURES( innerIterationCount < FAILSAFE_ITERATIONS_MED );
/* Calculate the overall size of the RDN */
size += ( int ) sizeofObject( rdnStartPtr->encodedRDNdataSize );
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
*length = size;
return( CRYPT_OK );
}
CHECK_RETVAL \
int sizeofDN( INOUT_OPT void *dnComponentList )
{
int length, status;
assert( dnComponentList == NULL || \
isWritePtr( dnComponentList, sizeof( DN_COMPONENT ) ) );
/* Null DNs produce a zero-length SEQUENCE */
if( dnComponentList == NULL )
return( sizeofObject( 0 ) );
status = preEncodeDN( dnComponentList, &length );
if( cryptStatusError( status ) )
return( status );
return( sizeofObject( length ) );
}
/* Write a DN */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int writeDN( INOUT STREAM *stream,
IN_OPT const void *dnComponentList,
IN_TAG const int tag )
{
DN_COMPONENT *dnComponentPtr;
int size, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( dnComponentList == NULL || \
isReadPtr( dnComponentList, sizeof( DN_COMPONENT ) ) );
REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
/* Special case for emptry DNs */
if( dnComponentList == NULL )
return( writeConstructed( stream, 0, tag ) );
status = preEncodeDN( ( DN_COMPONENT * ) dnComponentList, &size );
if( cryptStatusError( status ) )
return( status );
/* Write the DN */
writeConstructed( stream, size, tag );
for( dnComponentPtr = ( DN_COMPONENT * ) dnComponentList;
dnComponentPtr != NULL && cryptStatusOK( status );
dnComponentPtr = dnComponentPtr->next )
{
const DN_COMPONENT_INFO *dnComponentInfo = dnComponentPtr->typeInfo;
BYTE dnString[ MAX_ATTRIBUTE_SIZE + 8 ];
int dnStringLength;
/* Write the RDN wrapper */
if( dnComponentPtr->encodedRDNdataSize > 0 )
{
/* If it's the start of an RDN, write the RDN header */
writeSet( stream, dnComponentPtr->encodedRDNdataSize );
}
writeSequence( stream, dnComponentPtr->encodedAVAdataSize );
swrite( stream, dnComponentInfo->oid, \
sizeofOID( dnComponentInfo->oid ) );
/* Convert the string to an ASN.1-compatible format and write it
out */
status = copyToAsn1String( dnString, MAX_ATTRIBUTE_SIZE,
&dnStringLength, dnComponentPtr->value,
dnComponentPtr->valueLength,
dnComponentPtr->valueStringType );
if( cryptStatusError( status ) )
return( status );
if( dnComponentPtr->encodedStringType == BER_STRING_IA5 && \
!dnComponentInfo->ia5OK )
{
/* If an IA5String isn't allowed in this instance, use a
T61String instead */
dnComponentPtr->encodedStringType = BER_STRING_T61;
}
status = writeCharacterString( stream, dnString, dnStringLength,
dnComponentPtr->encodedStringType );
}
return( status );
}
/****************************************************************************
* *
* DN String Routines *
* *
****************************************************************************/
/* Read a DN in string form. Note that the ability to specify free-form DNs
means that users can create arbitrarily garbled and broken DNs (the
creation of weird nonstandard DNs is pretty much the main reason why the
DN-string capability exists). This includes DNs that can't be easily
handled through normal cryptlib facilities, for example ones where the CN
component consists of illegal characters or is in a form that isn't
usable as a search key for functions like cryptGetPublicKey(). If users
want to use this oddball-DN facility, it's up to them to make sure that
the resulting DN information works with whatever environment they're
intending to use it in */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -