📄 dn.c
字号:
int sizeofDN( void *dnComponentListHead )
{
return( sizeofObject( preEncodeDN( dnComponentListHead ) ) );
}
/* Write a DN */
int writeDN( STREAM *stream, const void *dnComponentListHead, const int tag )
{
DN_COMPONENT *dnComponentPtr;
const int size = preEncodeDN( ( DN_COMPONENT * ) dnComponentListHead );
int status = CRYPT_OK;
if( cryptStatusError( size ) )
return( size );
/* Write the DN */
writeConstructed( stream, size, tag );
for( dnComponentPtr = ( DN_COMPONENT * ) dnComponentListHead;
dnComponentPtr != NULL && cryptStatusOK( status );
dnComponentPtr = dnComponentPtr->next )
{
const DN_COMPONENT_INFO *dnComponentInfo = dnComponentPtr->typeInfo;
BYTE dnString[ MAX_ATTRIBUTE_SIZE ];
int dnStringLength;
/* Write the RDN wrapper */
if( dnComponentPtr->encodedRDNdataSize )
/* 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, &dnStringLength,
MAX_ATTRIBUTE_SIZE, 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 */
typedef struct {
const char *label, *text;
int labelLen, textLen; /* DN component label and value */
BOOLEAN isContinued; /* Whether further AVAs in this RDN */
} DN_STRING_INFO;
#define MAX_DNSTRING_COMPONENTS 64
static BOOLEAN parseDNString( DN_STRING_INFO *dnStringInfo,
const char *string, const int stringLength )
{
int stringPos = 0, stringInfoIndex = 0, i;
memset( dnStringInfo, 0,
sizeof( DN_STRING_INFO ) * ( MAX_DNSTRING_COMPONENTS + 1 ) );
/* Make sure there are no control characters in the string */
for( i = 0; i < stringLength; i++ )
if( ( string[ i ] & 0x7F ) < ' ' )
return( FALSE );
/* Verify that a DN string is of the form:
dnString ::= assignment '\0' | assignment ',' assignment
assignment ::= label '=' text */
do
{
DN_STRING_INFO *dnStringInfoPtr = &dnStringInfo[ stringInfoIndex ];
/* Check for label '=' ... */
for( i = stringPos; i < stringLength; i++ )
{
const char ch = string[ i ];
if( ch == '\\' )
return( FALSE );/* No escapes in the label component */
if( ch == '=' || ch == ',' || ch == '+' )
break;
}
if( i == stringPos || i == stringLength || \
string[ i ] == ',' || string[ i ] == '+' )
return( FALSE ); /* No text or no '=' or spurious ',' */
dnStringInfoPtr->label = string + stringPos;
dnStringInfoPtr->labelLen = i - stringPos;
stringPos = i + 1; /* Skip text + '=' */
/* Check for ... text { '\0' | ',' ... | '+' ... } */
for( i = stringPos;
i < stringLength && \
!( string[ i - 1 ] != '\\' && \
( string[ i ] == ',' || string[ i ] == '+' || \
string[ i ] == '=' ) ); i++ );
if( i == stringPos || string[ i ] == '=' )
return( FALSE ); /* No text or spurious '=' */
dnStringInfoPtr->text = string + stringPos;
dnStringInfoPtr->textLen = i - stringPos;
dnStringInfoPtr->isContinued = ( i < stringLength && \
string[ i ] == '+' ) ? TRUE : FALSE;
stringPos = i; /* Skip text + optional ',' */
if( stringPos != stringLength && \
++stringPos == stringLength )
/* Trailing ',' */
return( FALSE );
/* Strip leading and trailing whitespace on the label and text */
for( i = 0; i < dnStringInfoPtr->labelLen && \
dnStringInfoPtr->label[ i ] == ' '; i++ );
dnStringInfoPtr->label += i;
dnStringInfoPtr->labelLen -= i;
for( i = dnStringInfoPtr->labelLen; i > 0 && \
dnStringInfoPtr->label[ i - 1 ] == ' '; i-- );
dnStringInfoPtr->labelLen = i;
for( i = 0; i < dnStringInfoPtr->textLen && \
dnStringInfoPtr->text[ i ] == ' '; i++ );
dnStringInfoPtr->text += i;
dnStringInfoPtr->textLen -= i;
for( i = dnStringInfoPtr->textLen; i > 0 && \
dnStringInfoPtr->text[ i - 1 ] == ' '; i-- );
dnStringInfoPtr->textLen = i;
if( dnStringInfoPtr->labelLen <= 0 || dnStringInfoPtr->textLen <= 0 )
return( FALSE );
if( ++stringInfoIndex >= MAX_DNSTRING_COMPONENTS )
return( FALSE );
}
while( stringPos < stringLength );
return( TRUE );
}
int readDNstring( const char *string, const int stringLength,
void **dnComponentListHead )
{
DN_STRING_INFO dnStringInfo[ MAX_DNSTRING_COMPONENTS + 1 ];
DN_COMPONENT *dnComponentPtr;
int stringInfoIndex;
/* We have to perform the text string to DN translation in two stages
thanks to the backwards encoding required by RFC 1779, first we parse
it forwards to separate out the RDN components, then we move through
the parsed information backwards adding it to the RDN (with special
handling for multi-AVA RDNs as for writeDNstring()). Overall this
isn't so bad because it means we can perform a general firewall check
to make sure the DN string is well-formed and then leave the encoding
as a separate pass */
if( !parseDNString( dnStringInfo, string, stringLength ) )
return( CRYPT_ARGERROR_STR1 );
/* Find the end of the DN components */
for( stringInfoIndex = 0;
dnStringInfo[ stringInfoIndex + 1 ].label != NULL;
stringInfoIndex++ );
do
{
const DN_STRING_INFO *dnStringInfoPtr;
BOOLEAN isContinued;
/* Find the start of the RDN */
while( stringInfoIndex > 0 && \
dnStringInfo[ stringInfoIndex - 1 ].isContinued )
stringInfoIndex--;
dnStringInfoPtr = &dnStringInfo[ stringInfoIndex ];
do
{
const DN_COMPONENT_INFO *dnComponentInfo = NULL;
BYTE textBuffer[ MAX_ATTRIBUTE_SIZE + 1 ];
CRYPT_ATTRIBUTE_TYPE type;
int i, textIndex = 0, status;
/* Look up the DN component information */
for( i = 0; certInfoOIDs[ i ].oid != NULL; i++ )
if( ( strlen( certInfoOIDs[ i ].name ) == \
dnStringInfoPtr->labelLen && \
!strCompare( certInfoOIDs[ i ].name, dnStringInfoPtr->label,
dnStringInfoPtr->labelLen ) ) || \
( certInfoOIDs[ i ].altName != NULL && \
strlen( certInfoOIDs[ i ].altName ) == \
dnStringInfoPtr->labelLen && \
!strCompare( certInfoOIDs[ i ].altName, dnStringInfoPtr->label,
dnStringInfoPtr->labelLen ) ) )
{
dnComponentInfo = &certInfoOIDs[ i ];
break;
}
if( dnComponentInfo == NULL )
return( CRYPT_ARGERROR_STR1 );
type = ( dnComponentInfo->type != CRYPT_ATTRIBUTE_NONE ) ?
dnComponentInfo->type : i + DN_OID_OFFSET;
/* Convert the text to canonical form, removing any escapes for
special characters */
for( i = 0; i < dnStringInfoPtr->textLen; i++ )
{
int ch = dnStringInfoPtr->text[ i ];
if( ch == '\\' )
{
if( ++i >= dnStringInfoPtr->textLen )
return( CRYPT_ARGERROR_STR1 );
ch = dnStringInfoPtr->text[ i ];
}
textBuffer[ textIndex++ ] = ch;
}
/* Add the AVA to the DN */
if( type == CRYPT_CERTINFO_COUNTRYNAME )
{
/* If it's a country code, force it to uppercase as per ISO 3166 */
if( textIndex != 2 )
return( CRYPT_ARGERROR_STR1 );
textBuffer[ 0 ] = toUpper( textBuffer[ 0 ] );
textBuffer[ 1 ] = toUpper( textBuffer[ 1 ] );
status = insertDNstring( dnComponentListHead,
type, textBuffer, 2,
( dnStringInfoPtr->isContinued ) ? \
DN_FLAG_CONTINUED | DN_FLAG_NOCHECK : \
DN_FLAG_NOCHECK, NULL );
}
else
status = insertDNstring( dnComponentListHead,
type, textBuffer, textIndex,
( dnStringInfoPtr->isContinued ) ? \
DN_FLAG_CONTINUED | DN_FLAG_NOCHECK :
DN_FLAG_NOCHECK, NULL );
if( cryptStatusError( status ) )
{
deleteDN( dnComponentListHead );
return( status );
}
/* Move on to the next AVA */
isContinued = dnStringInfoPtr->isContinued;
dnStringInfoPtr++;
}
while( isContinued );
}
while( --stringInfoIndex >= 0 );
/* We're done, lock the DN against further updates */
for( dnComponentPtr = *dnComponentListHead; dnComponentPtr != NULL;
dnComponentPtr = dnComponentPtr->next )
dnComponentPtr->flags |= DN_FLAG_LOCKED;
return( CRYPT_OK );
}
/* Write a DN in string form */
int writeDNstring( STREAM *stream, const void *dnComponentListHead )
{
const DN_COMPONENT *dnComponentPtr = dnComponentListHead;
if( dnComponentPtr == NULL )
return( CRYPT_OK );
assert( isReadPtr( dnComponentPtr, sizeof( DN_COMPONENT ) ) );
/* Find the end of the DN string. We have to print the RDNs backwards
because of ISODE's Janet memorial backwards encoding */
while( dnComponentPtr->next != NULL )
dnComponentPtr = dnComponentPtr->next;
do
{
const DN_COMPONENT *dnComponentCursor;
BOOLEAN isContinued;
/* Find the start of the RDN */
while( dnComponentPtr->prev != NULL && \
( dnComponentPtr->prev->flags & DN_FLAG_CONTINUED ) )
dnComponentPtr = dnComponentPtr->prev;
dnComponentCursor = dnComponentPtr;
dnComponentPtr = dnComponentPtr->prev;
/* Print the current RDN */
do
{
const DN_COMPONENT_INFO *componentInfoPtr = \
dnComponentCursor->typeInfo;
int i;
/* Print the current AVA */
swrite( stream, componentInfoPtr->name,
strlen( componentInfoPtr->name ) );
sputc( stream, '=' );
for( i = 0; i < dnComponentCursor->valueLength; i++ )
{
const char ch = ( ( char * ) dnComponentCursor->value )[ i ];
if( ch == ',' || ch == '=' || ch == '+' || ch == ';' || \
ch == '\\' || ch == '"' )
sputc( stream, '\\' );
sputc( stream, ch );
}
/* If there are more AVAs in this RDN, print a continuation
indicator and move on to the next AVA */
isContinued = dnComponentCursor->flags & DN_FLAG_CONTINUED;
if( isContinued )
{
swrite( stream, " + ", 3 );
dnComponentCursor = dnComponentCursor->next;
}
}
while( isContinued );
/* If there are more components to come, print an RDN separator */
if( dnComponentPtr != NULL )
swrite( stream, ", ", 2 );
}
while( dnComponentPtr != NULL && sStatusOK( stream ) );
return( sGetStatus( stream ) );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -