📄 comp_get.c
字号:
/****************************************************************************
* *
* Get/Delete Certificate Components *
* Copyright Peter Gutmann 1997-2007 *
* *
****************************************************************************/
#include <stdio.h> /* For sprintf() */
#if defined( INC_ALL )
#include "cert.h"
#include "certattr.h"
#include "asn1.h"
#include "asn1_ext.h"
#else
#include "cert/cert.h"
#include "cert/certattr.h"
#include "misc/asn1.h"
#include "misc/asn1_ext.h"
#endif /* Compiler-specific includes */
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* The maximum magnitude of an individual OID arc. Anything larger than
this is most likely an error */
#define OID_ARC_MAX 0x1000000L /* 2 ^ 28 */
/* The minimum size for an OBJECT IDENTIFIER expressed as ASCII characters */
#define MIN_ASCII_OIDSIZE 7
/* Convert a binary OID to its text form */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
static int oidToText( IN_BUFFER( binaryOidLen ) const BYTE *binaryOID, \
IN_LENGTH_OID const int binaryOidLen,
OUT_BUFFER( maxOidLen, *oidLen ) char *oid,
IN_LENGTH_SHORT_MIN( 16 ) const int maxOidLen,
OUT_LENGTH_SHORT_Z int *oidLen )
{
int i, j, length, subLen;
long value;
assert( isReadPtr( binaryOID, binaryOidLen ) );
assert( isWritePtr( oid, maxOidLen ) );
assert( isWritePtr( oidLen, sizeof( int ) ) );
REQUIRES( binaryOidLen >= MIN_OID_SIZE && \
binaryOidLen <= MAX_OID_SIZE && \
binaryOidLen == sizeofOID( binaryOID ) );
REQUIRES( maxOidLen >= 16 && maxOidLen < MAX_INTLENGTH_SHORT );
/* Clear return values */
memset( oid, 0, min( 16, maxOidLen ) );
*oidLen = 0;
/* Pick apart the OID. This assumes that no OID component will be
larger than LONG_MAX */
i = binaryOID[ 2 ] / 40;
j = binaryOID[ 2 ] % 40;
if( i > 2 )
{
/* Handle special case for large j if i == 2 */
j += ( i - 2 ) * 40;
i = 2;
}
subLen = sprintf_s( oid, maxOidLen, "%d %d", i, j );
if( subLen < 3 )
return( CRYPT_ERROR_BADDATA );
length = subLen;
value = 0;
for( i = 3; i < binaryOidLen; i++ )
{
const BYTE data = binaryOID[ i ];
const long valTmp = value << 7;
if( valTmp < value || valTmp > OID_ARC_MAX )
return( CRYPT_ERROR_BADDATA ); /* Overflow */
value = valTmp | ( data & 0x7F );
if( value < 0 || value > OID_ARC_MAX )
return( CRYPT_ERROR_BADDATA ); /* Range error */
if( !( data & 0x80 ) )
{
subLen = sprintf_s( oid + length, maxOidLen - length,
" %ld", value );
if( subLen < 2 || subLen > maxOidLen - length )
return( CRYPT_ERROR_BADDATA );
length += subLen;
value = 0;
}
/* Make sure that we don't overflow the buffer (the value 20 is the
maximum magnitude of a 64-bit int plus space plus 1-byte
overflow) */
if( maxOidLen - length < 20 )
return( CRYPT_ERROR_BADDATA );
}
*oidLen = length;
return( CRYPT_OK );
}
/* Convert an ASCII OID arc sequence into an encoded OID and back. We allow
dots as well as whitespace for arc separators, these are an IETF-ism but
are in common use */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
static int scanValue( IN_BUFFER( strMaxLength ) const char *string,
IN_LENGTH_ATTRIBUTE const int strMaxLength,
OUT_INT_Z long *value )
{
long retVal = 0;
int dataLeft = strMaxLength;
assert( isReadPtr( string, strMaxLength ) );
assert( isWritePtr( value, sizeof( long ) ) );
REQUIRES( strMaxLength > 0 && strMaxLength < MAX_ATTRIBUTE_SIZE );
/* Clear return value */
*value = -1L;
if( dataLeft <= 0 || dataLeft > CRYPT_MAX_TEXTSIZE || \
!isDigit( *string ) )
return( -1 );
while( dataLeft > 0 && isDigit( *string ) )
{
const long retTmp = retVal * 10;
if( retTmp < retVal || retTmp > OID_ARC_MAX )
return( -1 ); /* Overflow */
retVal = retTmp + ( *string++ - '0' );
if( retVal < 0 || retVal > OID_ARC_MAX )
return( -1 ); /* Range error */
dataLeft--;
}
if( dataLeft > 0 && ( *string == ' ' || *string == '.' ) )
{
string++;
dataLeft--;
}
if( dataLeft > 0 && !isDigit( *string ) )
return( -1 );
*value = retVal;
return( strMaxLength - dataLeft );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
int textToOID( IN_BUFFER( oidLength ) const char *textOID,
IN_RANGE( MIN_ASCII_OIDSIZE, CRYPT_MAX_TEXTSIZE ) \
const int textOIDlength,
OUT_BUFFER( binaryOidMaxLen, binaryOidLen ) BYTE *binaryOID,
IN_LENGTH_SHORT const int binaryOidMaxLen,
OUT_LENGTH_SHORT_Z int *binaryOidLen )
{
char *textOidPtr;
long value, value2;
int length = 3, subLen, dataLeft, status;
assert( isReadPtr( textOID, textOIDlength ) );
assert( isWritePtr( binaryOID, binaryOidMaxLen ) );
assert( isWritePtr( binaryOidLen, sizeof( int ) ) );
REQUIRES( textOIDlength >= MIN_ASCII_OIDSIZE && \
textOIDlength <= CRYPT_MAX_TEXTSIZE );
REQUIRES( binaryOidMaxLen >= 5 && \
binaryOidMaxLen < MAX_INTLENGTH_SHORT );
/* Clear return value */
memset( binaryOID, 0, min( 16, binaryOidMaxLen ) );
*binaryOidLen = 0;
/* Perform some basic checks on the OID data */
status = dataLeft = strStripWhitespace( &textOidPtr, textOID,
textOIDlength );
if( cryptStatusError( status ) )
return( CRYPT_ERROR_BADDATA );
/* Make sure that the first two arcs are in order */
subLen = scanValue( textOidPtr, dataLeft, &value );
if( subLen <= 0 )
return( CRYPT_ERROR_BADDATA );
textOidPtr += subLen;
dataLeft -= subLen;
subLen = scanValue( textOidPtr, dataLeft, &value2 );
if( subLen <= 0 )
return( CRYPT_ERROR_BADDATA );
textOidPtr += subLen;
dataLeft -= subLen;
if( value < 0 || value > 2 || value2 < 1 || \
( ( value < 2 && value2 > 39 ) || ( value == 2 && value2 > 175 ) ) )
return( CRYPT_ERROR_BADDATA );
binaryOID[ 0 ] = 0x06; /* OBJECT IDENTIFIER tag */
binaryOID[ 2 ] = ( BYTE )( ( value * 40 ) + value2 );
/* Convert the remaining arcs */
while( dataLeft > 0 )
{
BOOLEAN hasHighBits = FALSE;
/* Scan the next value and write the high octets (if necessary) with
flag bits set, followed by the final octet */
subLen = scanValue( textOidPtr, dataLeft, &value );
if( subLen <= 0 )
return( CRYPT_ERROR_BADDATA );
textOidPtr += subLen;
dataLeft -= subLen;
if( value >= 0x200000L ) /* 2^21 */
{
if( length >= binaryOidMaxLen )
return( CRYPT_ERROR_BADDATA );
binaryOID[ length++ ] = ( BYTE ) ( 0x80 | ( value >> 21 ) );
value %= 0x200000L;
hasHighBits = TRUE;
}
if( ( value >= 0x4000 ) || hasHighBits ) /* 2^14 */
{
if( length >= binaryOidMaxLen )
return( CRYPT_ERROR_BADDATA );
binaryOID[ length++ ] = ( BYTE ) ( 0x80 | ( value >> 14 ) );
value %= 0x4000;
hasHighBits = TRUE;
}
if( ( value >= 0x80 ) || hasHighBits ) /* 2^7 */
{
if( length >= binaryOidMaxLen )
return( CRYPT_ERROR_BADDATA );
binaryOID[ length++ ] = ( BYTE ) ( 0x80 | ( value >> 7 ) );
value %= 128;
}
if( length >= binaryOidMaxLen )
return( CRYPT_ERROR_BADDATA );
binaryOID[ length++ ] = ( BYTE ) value;
}
binaryOID[ 1 ] = length - 2;
*binaryOidLen = length;
return( CRYPT_OK );
}
/****************************************************************************
* *
* DN/GeneralName Routines *
* *
****************************************************************************/
/* GeneralNames and DNs are handled via indirect selection. There are four
classes of field type that cover these names:
GNSelection = EXCLUDEDSUBTREES | ...
GNValue = OTHERNAME | ... | DIRECTORYNAME
DNSelection = SUBJECTNAME | ISSUERNAME | DIRECTORYNAME
DNValue = C | O | OU | CN | ...
Note that DIRECTORYNAME is present twice since it's both a component of a
GeneralName and a DN in its own right. GNSelection and DNSelection
components merely select a composite component, the primitive elements are
read and written via the GN and DN values. The selection process is as
follows:
GNSelection --+ (default = subjectAltName)
|
v
GN -+----------------> non-DirectoryName field
|
+--+ DirectoryName
|
DNSelection --+ (default = subjectName)
|
v
DN ------------------> DN field
Selecting a component can therefore lead through a complex heirarchy of
explicit and implicit selections, in the worst case being something like
subjectAltName -> directoryName -> DN field. DN and GeneralName
components may be absent (if we're selecting it in order to create it),
or present (if we're about to read it), or can be created when accessed
(if we're about to write to it). The handling is selected by the
SELECTION_OPTION type, if a certificate is in the high state then
MAY/CREATE options are implicitly converted to MUST_BE_PRESENT during the
selection process.
The selection is performed as follows:
set attribute:
selectionComponent:
selectDN subject | issuer | MAY_BE_ABSENT
selectGN attributeID | MAY_BE_ABSENT
- Select prior to use
valueComponent:
selectDN - | CREATE_IF_ABSENT
selectGN - | CREATE_IF_ABSENT
- To create DN/GeneralName before adding DN/GN
component/setting DN string
get attribute:
selectionComponent:
check subject | issuer | other | Presence check only
check attributeID
- Return T/F if present
valueComponent:
selectDN none | MUST_BE_PRESENT
selectGN none | MUST_BE_PRESENT
- To get DN/GeneralName component
delete attribute:
selectDN subject | issuers | MUST_BE_PRESENT
selectGN attributeID | MUST_BE_PRESENT
- To delete DN/GeneralName component
This code is cursed */
/* Check whether the currently selected extension is a GeneralName. We do
this both for simplicity and because isGeneralNameSelectionComponent() is
a complex macro that we want to avoid expanding as much as possible */
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN isGeneralNameSelected( const CERT_INFO *certInfoPtr )
{
assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
return( certInfoPtr->attributeCursor != NULL && \
isGeneralNameSelectionComponent( certInfoPtr->attributeCursor->fieldID ) ? \
TRUE : FALSE );
}
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN selectionInfoConsistent( const CERT_INFO *certInfoPtr )
{
assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
/* If the DN-in-extension flag is set there must be a DN selected */
if( certInfoPtr->currentSelection.dnPtr == NULL && \
certInfoPtr->currentSelection.dnInExtension )
return( FALSE );
/* If there's a DN selected and it's not in in an extension it must be
the subject or issuer DN */
if( certInfoPtr->currentSelection.dnPtr != NULL && \
!certInfoPtr->currentSelection.dnInExtension && \
certInfoPtr->currentSelection.dnPtr != &certInfoPtr->subjectName && \
certInfoPtr->currentSelection.dnPtr != &certInfoPtr->issuerName )
return( FALSE );
/* If there's a GeneralName selected there can't also be a saved
GeneralName present */
if( isGeneralNameSelected( certInfoPtr ) && \
certInfoPtr->currentSelection.generalName != CRYPT_ATTRIBUTE_NONE )
return( FALSE );
return( TRUE );
}
/* Check whether there's a DN in the currently-selected extension, and update
the various selection values if we find one */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int findDnInExtension( INOUT CERT_INFO *certInfoPtr,
const BOOLEAN updateCursor )
{
const CRYPT_ATTRIBUTE_TYPE attributeID = certInfoPtr->attributeCursor->attributeID;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -