📄 comp_set.c
字号:
/* If there's no attributes present or no disallowed attribute template,
we're done */
if( certInfoPtr->attributes == NULL || templateListPtr == NULL )
return( CRYPT_OK );
/* Walk down the template attribute list applying each one in turn to
the certificate attributes */
for( attributeListCursor = templateListPtr, iterationCount = 0;
attributeListCursor != NULL && \
!isBlobAttribute( attributeListCursor ) && \
iterationCount < FAILSAFE_ITERATIONS_MAX;
attributeListCursor = attributeListCursor->next, iterationCount++ )
{
ATTRIBUTE_LIST *attributeList;
int value;
/* Check to see whether there's a constrained attribute present in
the certificate attributes and if it is, whether it conflicts
with the constraining attribute */
attributeList = findAttributeField( certInfoPtr->attributes,
attributeListCursor->fieldID,
attributeListCursor->subFieldID );
if( attributeList == NULL || \
!( attributeList->intValue & attributeListCursor->intValue ) )
continue;
/* If the certificate attribute was provided through the application
of PKI user data (indicated by it having the locked flag set),
allow it even if it conflicts with the constraining attribute.
This is permitted because the PKI user data was explicitly set by
the issuing CA rather than being user-supplied in the certificate
request so it has to be OK, or at least CA-approved */
if( attributeList->flags & ATTR_FLAG_LOCKED )
continue;
/* The attribute contains a value that's disallowed by the
constraining attribute, correct it if possible */
value = attributeList->intValue & ~attributeListCursor->intValue;
if( !value )
{
/* The attribute contains only invalid bits and can't be
permitted */
certInfoPtr->errorLocus = attributeList->fieldID;
certInfoPtr->errorType = CRYPT_ERRTYPE_ATTR_VALUE;
return( CRYPT_ERROR_INVALID );
}
attributeList->intValue = value; /* Set adjusted value */
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MAX );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Serial-Number Routines *
* *
****************************************************************************/
/* Set the serial number for a certificate. Ideally we would store this as
a static value in the configuration database but this has three
disadvantages: Updating the serial number updates the entire
configuration database (including things the user might not want
updated), if the configuration database update fails the serial number
never changes, and the predictable serial number allows tracking of the
number of certificates which have been issued by the CA. Because of this
we just use a 64-bit nonce if the user doesn't supply a value */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int setSerialNumber( INOUT CERT_INFO *certInfoPtr,
IN_BUFFER_OPT( serialNumberLength ) const void *serialNumber,
IN_LENGTH_SHORT_Z const int serialNumberLength )
{
MESSAGE_DATA msgData;
BYTE buffer[ 128 + 8 ];
void *serialNumberPtr;
int length = ( serialNumberLength > 0 ) ? \
serialNumberLength : DEFAULT_SERIALNO_SIZE;
int bufPos = 0, status;
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
assert( ( serialNumber == NULL && serialNumberLength == 0 ) || \
( isReadPtr( serialNumber, serialNumberLength ) ) );
REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN || \
certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION );
REQUIRES( ( serialNumber == NULL && serialNumberLength == 0 ) || \
( serialNumber != NULL && \
serialNumberLength > 0 && \
serialNumberLength <= MAX_SERIALNO_SIZE ) );
/* If a serial number has already been set explicitly, don't override
it with an implicitly-set one */
serialNumberPtr = \
( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION ) ? \
certInfoPtr->cCertReq->serialNumber : \
certInfoPtr->cCertCert->serialNumber;
if( serialNumberPtr != NULL )
{
assert( isReadPtr( serialNumberPtr, SERIALNO_BUFSIZE ) );
ENSURES( serialNumber == NULL && serialNumberLength == 0 );
return( CRYPT_OK );
}
serialNumberPtr = \
( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION ) ? \
certInfoPtr->cCertReq->serialNumberBuffer : \
certInfoPtr->cCertCert->serialNumberBuffer;
/* If we're using user-supplied serial number data, canonicalise it into
a form suitable for use as an INTEGER-hole */
if( serialNumber != NULL )
{
STREAM stream;
assert( isReadPtr( serialNumber, serialNumberLength ) );
sMemOpen( &stream, buffer, 128 );
status = writeInteger( &stream, serialNumber, serialNumberLength,
DEFAULT_TAG );
length = stell( &stream ) - 2;
sMemDisconnect( &stream );
bufPos = 2; /* Skip tag + length */
if( cryptStatusError( status ) )
return( status );
}
else
{
/* Generate a random (but fixed-length) serial number and ensure
that the first byte of the value we use is nonzero (to guarantee
a DER encoding) and clear the high bit to provide a constant-
length ASN.1 encoded value */
setMessageData( &msgData, buffer, DEFAULT_SERIALNO_SIZE + 1 );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_RANDOM_NONCE );
if( cryptStatusError( status ) )
return( status );
buffer[ 0 ] &= 0x7F; /* Clear the sign bit */
if( buffer[ 0 ] == 0 )
{
/* The first byte is zero, try for a nonzero byte in the extra
data that we fetched. If that's zero too, just set it to 1 */
buffer[ 0 ] = buffer[ DEFAULT_SERIALNO_SIZE ] & 0x7F;
if( buffer[ 0 ] == 0 )
buffer[ 0 ] = 1;
}
}
/* Copy across the canonicalised serial number value */
if( length >= SERIALNO_BUFSIZE && \
( serialNumberPtr = clDynAlloc( "setSerialNumber", length ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
if( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION )
{
certInfoPtr->cCertReq->serialNumber = serialNumberPtr;
certInfoPtr->cCertReq->serialNumberLength = length;
}
else
{
certInfoPtr->cCertCert->serialNumber = serialNumberPtr;
certInfoPtr->cCertCert->serialNumberLength = length;
}
memcpy( serialNumberPtr, buffer + bufPos, length );
return( CRYPT_OK );
}
/* Compare a serial number in canonical form to a generic serial number
with special handling for leading-zero truncation. This one can get a
bit tricky because Microsoft fairly consistently encode serial numbers
incorrectly so we normalise the values to have no leading zero, which is
the lowest common denominator */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
BOOLEAN compareSerialNumber( IN_BUFFER( canonSerialNumberLength ) \
const void *canonSerialNumber,
IN_LENGTH_SHORT const int canonSerialNumberLength,
IN_BUFFER( serialNumberLength ) \
const void *serialNumber,
IN_LENGTH_SHORT const int serialNumberLength )
{
const BYTE *canonSerialNumberPtr = canonSerialNumber;
const BYTE *serialNumberPtr = serialNumber;
int canonSerialLength = canonSerialNumberLength;
int serialLength = serialNumberLength;
assert( isReadPtr( canonSerialNumber, canonSerialNumberLength ) );
assert( isReadPtr( serialNumber, serialNumberLength ) );
/* Internal serial numbers are canonicalised so all we need to do is
strip a possible leading zero */
if( canonSerialNumberPtr[ 0 ] == 0 )
{
canonSerialNumberPtr++;
canonSerialLength--;
}
ENSURES( canonSerialLength == 0 || canonSerialNumberPtr[ 0 ] );
/* Serial numbers from external sources can be arbitarily strangely
encoded so we strip leading zeroes until we get to actual data */
while( serialLength > 0 && serialNumberPtr[ 0 ] == 0 )
{
serialNumberPtr++;
serialLength--;
}
/* Finally we've got them in a form where we can compare them */
if( canonSerialLength == serialLength && \
!memcmp( canonSerialNumberPtr, serialNumberPtr, serialLength ) )
return( TRUE );
return( FALSE );
}
/****************************************************************************
* *
* Copy Certificate Request Info *
* *
****************************************************************************/
/* Copy certificate request info into a certificate object. This copies the
public key context, the DN, any valid attributes, and any other relevant
bits and pieces if it's a CRMF request */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int copyCertReqInfo( INOUT CERT_INFO *certInfoPtr,
INOUT CERT_INFO *certRequestInfoPtr )
{
int status;
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
assert( isWritePtr( certRequestInfoPtr, sizeof( CERT_INFO ) ) );
REQUIRES( certRequestInfoPtr->type == CRYPT_CERTTYPE_CERTREQUEST || \
certRequestInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT );
/* Copy the public key context, the DN, and the attributes. Type
checking has already been performed by the kernel. We copy the
attributes across after the DN because that copy is the hardest to
undo: If there are already attributes present then the copied
attributes would be mixed in among them so it's not really possible
to undo the copy later without performing a complex selective
delete */
status = copyDN( &certInfoPtr->subjectName,
certRequestInfoPtr->subjectName );
if( cryptStatusOK( status ) )
{
if( certRequestInfoPtr->flags & CERT_FLAG_DATAONLY )
{
status = copyPublicKeyInfo( certInfoPtr, CRYPT_UNUSED,
certRequestInfoPtr );
}
else
{
status = copyPublicKeyInfo( certInfoPtr,
certRequestInfoPtr->iPubkeyContext,
NULL );
}
}
if( cryptStatusOK( status ) && \
certRequestInfoPtr->attributes != NULL )
{
status = copyAttributes( &certInfoPtr->attributes,
certRequestInfoPtr->attributes,
&certInfoPtr->errorLocus,
&certInfoPtr->errorType );
if( cryptStatusError( status ) )
deleteDN( &certInfoPtr->subjectName );
}
if( cryptStatusError( status ) )
return( status );
/* If it's a CRMF request there could also be a validity period
specified */
if( certRequestInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT )
{
const time_t currentTime = getApproxTime();
/* We don't allow start times backdated by more than a year or end
times before the start time. Since these are trivial things we
don't abort if there's a problem but just quietly fix the value */
if( certRequestInfoPtr->startTime > MIN_TIME_VALUE && \
certRequestInfoPtr->startTime > currentTime - ( 86400L * 365 ) )
certInfoPtr->startTime = certRequestInfoPtr->startTime;
if( certRequestInfoPtr->endTime > MIN_TIME_VALUE && \
certRequestInfoPtr->endTime > certInfoPtr->startTime )
certInfoPtr->endTime = certRequestInfoPtr->endTime;
}
return( CRYPT_OK );
}
/* Copy what we need to identify the certificate to be revoked and any
revocation information into a certificate object */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int copyRevReqInfo( INOUT CERT_INFO *certInfoPtr,
INOUT CERT_INFO *revRequestInfoPtr )
{
int status;
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
assert( isWritePtr( revRequestInfoPtr, sizeof( CERT_INFO ) ) );
status = copyRevocationInfo( certInfoPtr, revRequestInfoPtr );
if( cryptStatusError( status ) || \
revRequestInfoPtr->attributes == NULL )
return( status );
return( copyRevocationAttributes( &certInfoPtr->attributes,
revRequestInfoPtr->attributes ) );
}
/* Copy revocation information from an RTCS or OCSP request to a response */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int copyRtcsReqInfo( INOUT CERT_INFO *certInfoPtr,
INOUT CERT_INFO *rtcsRequestInfoPtr )
{
int status;
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
assert( isWritePtr( rtcsRequestInfoPtr, sizeof( CERT_INFO ) ) );
/* Copy the certificate validity information and extensions */
status = copyValidityEntries( &certInfoPtr->cCertVal->validityInfo,
rtcsRequestInfoPtr->cCertVal->validityInfo );
if( cryptStatusOK( status ) )
status = copyOCSPRequestAttributes( &certInfoPtr->attributes,
rtcsRequestInfoPtr->attributes );
return( status );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int copyOcspReqInfo( INOUT CERT_INFO *certInfoPtr,
INOUT CERT_INFO *ocspRequestInfoPtr )
{
int status;
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
assert( isWritePtr( ocspRequestInfoPtr, sizeof( CERT_INFO ) ) );
/* Copy the revocation information and extensions */
status = copyRevocationEntries( &certInfoPtr->cCertRev->revocations,
ocspRequestInfoPtr->cCertRev->revocations );
if( cryptStatusOK( status ) )
status = copyOCSPRequestAttributes( &certInfoPtr->attributes,
ocspRequestInfoPtr->attributes );
if( cryptStatusError( status ) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -