📄 comp_set.c
字号:
/****************************************************************************
* *
* Set Certificate Components *
* Copyright Peter Gutmann 1997-2005 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
#include "cert.h"
#include "certattr.h"
#include "asn1.h"
#include "asn1_ext.h"
#elif defined( INC_CHILD )
#include "cert.h"
#include "certattr.h"
#include "../misc/asn1.h"
#include "../misc/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 */
/* Prototypes for functions in comp_get.c */
int moveCursorToField( CERT_INFO *certInfoPtr,
const CRYPT_ATTRIBUTE_TYPE certInfoType );
int selectGeneralName( CERT_INFO *certInfoPtr,
const CRYPT_ATTRIBUTE_TYPE certInfoType,
const SELECTION_OPTION option );
int selectDN( CERT_INFO *certInfoPtr, const CRYPT_ATTRIBUTE_TYPE certInfoType,
const SELECTION_OPTION option );
void syncSelection( CERT_INFO *certInfoPtr );
time_t *getRevocationTimePtr( const CERT_INFO *certInfoPtr );
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* Copy the encoded issuer DN */
static int copyIssuerDnData( CERT_INFO *destCertInfoPtr,
const CERT_INFO *srcCertInfoPtr )
{
void *dnDataPtr;
assert( srcCertInfoPtr->issuerDNptr != NULL );
if( ( dnDataPtr = clAlloc( "copyIssuerDnData",
srcCertInfoPtr->issuerDNsize ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
memcpy( dnDataPtr, srcCertInfoPtr->issuerDNptr,
srcCertInfoPtr->issuerDNsize );
destCertInfoPtr->issuerDNptr = destCertInfoPtr->issuerDNdata = dnDataPtr;
destCertInfoPtr->issuerDNsize = srcCertInfoPtr->issuerDNsize;
return( CRYPT_OK );
}
/* Copy revocation information into a CRL or revocation request */
static int copyRevocationInfo( CERT_INFO *certInfoPtr,
const CERT_INFO *revInfoPtr )
{
int status = CRYPT_OK;
assert( certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION );
assert( revInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
revInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
revInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN || \
revInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION );
/* If there's an issuer name recorded, make sure that it matches the one
in the cert that's being added */
if( certInfoPtr->issuerDNptr != NULL )
{
if( certInfoPtr->issuerDNsize != revInfoPtr->issuerDNsize || \
memcmp( certInfoPtr->issuerDNptr, revInfoPtr->issuerDNptr,
certInfoPtr->issuerDNsize ) )
{
setErrorInfo( certInfoPtr, CRYPT_CERTINFO_ISSUERNAME,
CRYPT_ERRTYPE_ATTR_VALUE );
status = CRYPT_ERROR_INVALID;
}
}
else
/* There's no issuer name present yet, set the CRL issuer name to
the cert's issuer to make sure that we can't add certs or sign
the CRL with a different issuer. We do this here rather than
after setting the revocation list entry because of the
difficulty of undoing the revocation entry addition */
status = copyIssuerDnData( certInfoPtr, revInfoPtr );
if( cryptStatusError( status ) )
return( status );
/* Add the cert information to the revocation list and make it the
currently selected entry. The ID type isn't quite an
issueAndSerialNumber, but the checking code eventually converts
it into this form using the supplied issuer cert DN */
if( revInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION )
status = addRevocationEntry( &certInfoPtr->cCertRev->revocations,
&certInfoPtr->cCertRev->currentRevocation,
CRYPT_IKEYID_ISSUERANDSERIALNUMBER,
revInfoPtr->cCertReq->serialNumber,
revInfoPtr->cCertReq->serialNumberLength,
FALSE );
else
status = addRevocationEntry( &certInfoPtr->cCertRev->revocations,
&certInfoPtr->cCertRev->currentRevocation,
CRYPT_IKEYID_ISSUERANDSERIALNUMBER,
revInfoPtr->cCertCert->serialNumber,
revInfoPtr->cCertCert->serialNumberLength,
FALSE );
if( status == CRYPT_ERROR_DUPLICATE )
/* If this cert is already present in the list, set the extended
error code for it */
setErrorInfo( certInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
CRYPT_ERRTYPE_ATTR_PRESENT );
return( status );
}
/* Convert a DN in string form into a certificate DN */
static int getEncodedDn( CERT_INFO *certInfoPtr, const void *dnString,
const int dnStringLength )
{
SELECTION_STATE savedState;
int status;
/* If there's already a DN set, we can't do anything else */
saveSelectionState( savedState, certInfoPtr );
status = selectDN( certInfoPtr, CRYPT_ATTRIBUTE_NONE, MUST_BE_PRESENT );
if( cryptStatusOK( status ) && \
*certInfoPtr->currentSelection.dnPtr == NULL )
/* There's a DN selected but it's empty, we're OK */
status = CRYPT_ERROR;
restoreSelectionState( savedState, certInfoPtr );
if( cryptStatusOK( status ) )
return( CRYPT_ERROR_INITED );
status = selectDN( certInfoPtr, CRYPT_ATTRIBUTE_NONE, CREATE_IF_ABSENT );
if( cryptStatusError( status ) )
return( status );
/* Read the entire DN from its string form into the selected DN */
status = readDNstring( dnString, dnStringLength,
certInfoPtr->currentSelection.dnPtr );
if( cryptStatusOK( status ) && \
certInfoPtr->currentSelection.updateCursor )
/* If we couldn't update the cursor earlier on because the attribute
field in question hadn't been created yet, do it now */
selectGeneralName( certInfoPtr,
certInfoPtr->currentSelection.generalName,
MAY_BE_ABSENT );
return( status );
}
/* The OCSPv1 ID doesn't contain any usable fields so we pre-encode it when
the cert is added to the OCSP request and treat it as a blob thereafter */
static int writeOCSPv1ID( STREAM *stream, const CERT_INFO *certInfoPtr,
const void *issuerKeyHash )
{
HASHFUNCTION hashFunction;
BYTE hashBuffer[ CRYPT_MAX_HASHSIZE ];
int hashSize;
assert( certInfoPtr->issuerDNptr != NULL );
assert( certInfoPtr->cCertCert->serialNumber != NULL );
/* Get the issuerName hash */
getHashParameters( CRYPT_ALGO_SHA, &hashFunction, &hashSize );
hashFunction( NULL, hashBuffer, certInfoPtr->issuerDNptr,
certInfoPtr->issuerDNsize, HASH_ALL );
/* Write the request data */
writeSequence( stream,
sizeofAlgoID( CRYPT_ALGO_SHA ) + \
sizeofObject( hashSize ) + sizeofObject( hashSize ) + \
sizeofInteger( certInfoPtr->cCertCert->serialNumber,
certInfoPtr->cCertCert->serialNumberLength ) );
writeAlgoID( stream, CRYPT_ALGO_SHA );
writeOctetString( stream, hashBuffer, hashSize, DEFAULT_TAG );
writeOctetString( stream, issuerKeyHash, 20, DEFAULT_TAG );
return( writeInteger( stream, certInfoPtr->cCertCert->serialNumber,
certInfoPtr->cCertCert->serialNumberLength,
DEFAULT_TAG ) );
}
/* Sanitise cert attributes based on a user-supplied template. This is
used to prevent a user from supplying potentially dangerous attributes
in a cert request, for example to request a CA certificate by setting the
basicConstraints/keyUsage = CA extensions in the request in a manner that
would result in the creation of a CA cert when the request is processed.
We use an allow-all default rather than deny-all since deny-all would
require the caller to specify a vast range of (mostly never-used)
attributes to permit, when usually all they want to block is the CA flag
and equivalent mechanisms */
static int sanitiseCertAttributes( CERT_INFO *certInfoPtr,
const ATTRIBUTE_LIST *templateListPtr )
{
const ATTRIBUTE_LIST *attributeListCursor;
/* 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;
attributeListCursor != NULL && \
!isBlobAttribute( attributeListCursor );
attributeListCursor = attributeListCursor->next )
{
ATTRIBUTE_LIST *attributeList;
int value;
/* Check to see whether there's a constrained attribute present in
the cert 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 cert 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 cert request,
so it has to be OK */
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 */
}
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 config 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 */
int setSerialNumber( CERT_INFO *certInfoPtr, const void *serialNumber,
const int serialNumberLength )
{
RESOURCE_DATA msgData;
BYTE buffer[ 128 ];
void *serialNumberPtr;
int length = ( serialNumberLength > 0 ) ? \
serialNumberLength : DEFAULT_SERIALNO_SIZE;
int bufPos = 0, status;
assert( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN || \
certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION );
assert( ( serialNumber == NULL && serialNumberLength == 0 ) || \
( serialNumber != NULL && serialNumberLength > 0 && \
serialNumberLength <= 100 ) );
/* 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 ) );
assert( 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 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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -