📄 certstr.c
字号:
( DN_COMPONENT * ) malloc( sizeof( DN_COMPONENT ) ) ) == NULL ) || \
( srcPtr->value != srcPtr->smallValue && \
( valuePtr = malloc( srcPtr->valueLength ) ) == NULL ) )
{
if( newElement != NULL )
free( newElement );
deleteDN( dnDest );
return( CRYPT_ERROR_MEMORY );
}
memcpy( newElement, srcPtr, sizeof( DN_COMPONENT ) );
if( srcPtr->value == srcPtr->smallValue )
newElement->value = newElement->smallValue;
else
{
memcpy( valuePtr, srcPtr->value, srcPtr->valueLength );
newElement->value = valuePtr;
}
/* Link it into the list */
if( destPtr == NULL )
{
*dnDest = destPtr = newElement;
newElement->prev = newElement->next = NULL;
}
else
{
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, DN's which act as filters
(eg path constraints) may not have the lower DN parts present, and cert
requests submitted to CA's 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 (????)
rfc822Mailbox into an rfc822Name */
static 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;
const int dummy = CRYPT_UNUSED;
int status;
/* If there's no PKCS #9 email address present, try for a (????) 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 */
saveSelectionState( selectionState, certInfoPtr );
addCertComponent( certInfoPtr, altNameType, &dummy, 0 );
status = addCertComponent( certInfoPtr, CRYPT_CERTINFO_RFC822NAME,
emailComponent->value,
emailComponent->valueLength );
if( status == CRYPT_ERROR_INITED )
/* 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 */
status = CRYPT_OK;
else
/* It was successfully copied over, delete the copy in the DN */
deleteComponent( dnListHead, emailComponent );
restoreSelectionState( selectionState, certInfoPtr );
return( status );
}
int convertEmailAddress( CERT_INFO *certInfoPtr )
{
int status;
status = convertEmail( certInfoPtr, &certInfoPtr->subjectName,
CRYPT_CERTINFO_SUBJECTALTNAME );
if( cryptStatusOK( status ) )
status = convertEmail( certInfoPtr, &certInfoPtr->issuerName,
CRYPT_CERTINFO_ISSUERALTNAME );
return( status );
}
/* Perform the pre-encoding processing for a DN */
static int preEncodeDN( const DN_COMPONENT *dnComponentListHead )
{
DN_COMPONENT *dnComponentPtr = ( DN_COMPONENT * ) dnComponentListHead;
int size = 0;
assert( dnComponentPtr != NULL );
/* If we're being fed an entry in the middle of a DN, move back to the
start */
if( dnComponentPtr != NULL )
while( dnComponentPtr->prev != NULL )
dnComponentPtr = dnComponentPtr->prev;
/* Walk down the DN pre-encoding each AVA */
while( dnComponentPtr != NULL )
{
DN_COMPONENT *rdnStartPtr = dnComponentPtr;
BOOLEAN isContinued;
/* Calculate the size of every AVA in this RDN */
do
{
const DN_COMPONENT_INFO *dnComponentInfo = dnComponentPtr->typeInfo;
dnComponentPtr->encodedAVAdataSize = \
sizeofOID( dnComponentInfo->oid ) + \
( int ) sizeofObject( dnComponentPtr->valueLength );
dnComponentPtr->encodedRDNdataSize = 0;
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 );
}
int sizeofDN( const 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( dnComponentListHead );
/* Write the DN */
if( tag == DEFAULT_TAG )
writeSequence( stream, size );
else
writeConstructed( stream, size, tag );
for( dnComponentPtr = ( DN_COMPONENT * ) dnComponentListHead;
dnComponentPtr != NULL; dnComponentPtr = dnComponentPtr->next )
{
const DN_COMPONENT_INFO *dnComponentInfo = dnComponentPtr->typeInfo;
int tag;
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 ) );
switch( dnComponentPtr->stringType )
{
case STRINGTYPE_UNICODE:
tag = BER_STRING_BMP;
break;
case STRINGTYPE_PRINTABLE:
tag = BER_STRING_PRINTABLE;
break;
case STRINGTYPE_IA5:
tag = dnComponentInfo->IA5OK ? BER_STRING_IA5 : BER_STRING_T61;
break;
case STRINGTYPE_T61:
tag = BER_STRING_T61;
break;
default:
assert( NOTREACHED );
}
writeCharacterString( stream, dnComponentPtr->value,
dnComponentPtr->valueLength, tag );
}
return( sGetStatus( stream ) );
}
/* Write a DN in string form */
int writeDNstring( STREAM *stream, const void *dnComponentListHead )
{
const DN_COMPONENT *dnComponentPtr = dnComponentListHead;
if( dnComponentPtr == NULL )
return( CRYPT_OK );
/* 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 );
return( sGetStatus( stream ) );
}
/* 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,
ASN1_STRINGTYPE *stringType )
{
BYTE oid[ MAX_OID_SIZE ];
int oidLength, tag, i, status;
/* Clear return values */
*type = CRYPT_ATTRIBUTE_NONE;
*length = 0;
*stringType = STRINGTYPE_NONE;
/* Read the start of the AVA and determine the type from the AttributeType
field. If we find something which cryptlib doesn'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 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 = readTag( 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 */
readShortLength( stream );
sgetc( stream ); /* Skip bit count */
tag = readTag( stream );
}
switch( tag )
{
case BER_STRING
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -