📄 comp_set.c
字号:
/****************************************************************************
* *
* Set Certificate Components *
* Copyright Peter Gutmann 1997-2007 *
* *
****************************************************************************/
#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 *
* *
****************************************************************************/
/* Copy the encoded issuer DN */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int copyIssuerDnData( INOUT CERT_INFO *destCertInfoPtr,
const CERT_INFO *srcCertInfoPtr )
{
void *dnDataPtr;
assert( isWritePtr( destCertInfoPtr, sizeof( CERT_INFO ) ) );
assert( isReadPtr( srcCertInfoPtr, sizeof( CERT_INFO ) ) );
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 */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int copyRevocationInfo( INOUT CERT_INFO *certInfoPtr,
const CERT_INFO *revInfoPtr )
{
int status = CRYPT_OK;
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
assert( isReadPtr( revInfoPtr, sizeof( CERT_INFO ) ) );
REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION );
REQUIRES( 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 certificate 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 certificate's issuer to make sure that we can't add
certificates 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 certificate 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 certificate 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 certificate is already present in the list set the
extended error code for it */
setErrorInfo( certInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
CRYPT_ERRTYPE_ATTR_PRESENT );
}
return( status );
}
/* Copy public key data into a certificate object */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int copyPublicKeyInfo( INOUT CERT_INFO *certInfoPtr,
IN_HANDLE_OPT const CRYPT_HANDLE cryptHandle,
IN_OPT const CERT_INFO *srcCertInfoPtr )
{
void *publicKeyInfoPtr;
int length = DUMMY_INIT, status;
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
assert( ( isHandleRangeValid( cryptHandle ) && \
srcCertInfoPtr == NULL ) || \
( cryptHandle == CRYPT_UNUSED && \
isReadPtr( srcCertInfoPtr, sizeof( CERT_INFO ) ) ) );
REQUIRES( ( isHandleRangeValid( cryptHandle ) && \
srcCertInfoPtr == NULL ) || \
( cryptHandle == CRYPT_UNUSED && \
srcCertInfoPtr != NULL ) );
/* Make sure that we haven't already got a public key present */
if( certInfoPtr->iPubkeyContext != CRYPT_ERROR || \
certInfoPtr->publicKeyInfo != NULL )
{
setErrorInfo( certInfoPtr, CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO,
CRYPT_ERRTYPE_ATTR_PRESENT );
return( CRYPT_ERROR_INITED );
}
/* If we've been given a data-only certificate copy over the public key
data */
if( srcCertInfoPtr != NULL )
{
REQUIRES( memcmp( srcCertInfoPtr->publicKeyID,
"\x00\x00\x00\x00\x00\x00\x00\x00", 8 ) );
REQUIRES( ( ( BYTE * ) srcCertInfoPtr->publicKeyInfo )[ 0 ] == 0x30 );
length = srcCertInfoPtr->publicKeyInfoSize;
if( ( publicKeyInfoPtr = clAlloc( "copyPublicKeyInfo", length ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
memcpy( publicKeyInfoPtr, srcCertInfoPtr->publicKeyInfo, length );
certInfoPtr->publicKeyAlgo = srcCertInfoPtr->publicKeyAlgo;
certInfoPtr->publicKeyFeatures = srcCertInfoPtr->publicKeyFeatures;
memcpy( certInfoPtr->publicKeyID, srcCertInfoPtr->publicKeyID,
KEYID_SIZE );
}
else
{
CRYPT_CONTEXT iCryptContext;
MESSAGE_DATA msgData;
/* Get the context handle. All other checking has already been
performed by the kernel */
status = krnlSendMessage( cryptHandle, IMESSAGE_GETDEPENDENT,
&iCryptContext, OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
{
setErrorInfo( certInfoPtr, CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO,
CRYPT_ERRTYPE_ATTR_VALUE );
return( status );
}
ENSURES( cryptStatusOK( \
krnlSendMessage( iCryptContext, IMESSAGE_CHECK, NULL,
MESSAGE_CHECK_PKC ) ) );
/* Get the key information */
status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
&certInfoPtr->publicKeyAlgo,
CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
&certInfoPtr->publicKeyFeatures,
CRYPT_IATTRIBUTE_KEYFEATURES );
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, certInfoPtr->publicKeyID, KEYID_SIZE );
status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_KEYID );
}
if( cryptStatusError( status ) )
return( status );
/* Copy over the public-key data. We copy the data rather than
keeping a reference to the context for two reasons. Firstly,
when the certificate is transitioned into the high state it will
constrain the attached context so a context shared between two
certificates could be constrained in unexpected ways. Secondly,
the context could be a private-key context and attaching that to
a certificate would be rather inappropriate. Furthermore, the
constraint issue is even more problematic in that a context
constrained by an encryption-only request could then no longer be
used to sign the request or a PKI protocol message containing the
request */
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_KEY_SPKI );
if( cryptStatusError( status ) )
return( status );
length = msgData.length;
if( ( publicKeyInfoPtr = clAlloc( "copyPublicKeyInfo", length ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
msgData.data = publicKeyInfoPtr;
status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_KEY_SPKI );
if( cryptStatusError( status ) )
return( status );
}
certInfoPtr->publicKeyData = certInfoPtr->publicKeyInfo = \
publicKeyInfoPtr;
certInfoPtr->publicKeyInfoSize = length;
certInfoPtr->flags |= CERT_FLAG_DATAONLY;
return( CRYPT_OK );
}
/* Convert a DN in string form into a certificate DN */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int getEncodedDn( INOUT CERT_INFO *certInfoPtr,
IN_BUFFER( dnStringLength ) const void *dnString,
IN_LENGTH_ATTRIBUTE const int dnStringLength )
{
SELECTION_STATE savedState;
int status;
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
assert( isReadPtr( dnString, dnStringLength ) );
REQUIRES( dnStringLength > 0 && dnStringLength < MAX_INTLENGTH_SHORT );
/* 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( certInfoPtr->currentSelection.dnPtr,
dnString, dnStringLength );
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. Since this
is merely a side-effect of this operation we ignore the return
status and return the main result status */
( void ) 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 certificate is added to the OCSP request and treat it as a blob
thereafter */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int writeOCSPv1ID( INOUT STREAM *stream,
const CERT_INFO *certInfoPtr,
IN_BUFFER( issuerKeyHashLength ) \
const void *issuerKeyHash,
IN_LENGTH_FIXED( KEYID_SIZE ) \
const int issuerKeyHashLength )
{
HASHFUNCTION_ATOMIC hashFunctionAtomic;
BYTE hashBuffer[ CRYPT_MAX_HASHSIZE + 8 ];
int hashSize;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
REQUIRES( issuerKeyHashLength == KEYID_SIZE );
REQUIRES( certInfoPtr->issuerDNptr != NULL );
REQUIRES( certInfoPtr->cCertCert->serialNumber != NULL );
/* Get the issuerName hash */
getHashAtomicParameters( CRYPT_ALGO_SHA1, &hashFunctionAtomic, &hashSize );
hashFunctionAtomic( hashBuffer, CRYPT_MAX_HASHSIZE,
certInfoPtr->issuerDNptr,
certInfoPtr->issuerDNsize );
/* Write the request data */
writeSequence( stream,
sizeofAlgoID( CRYPT_ALGO_SHA1 ) + \
sizeofObject( hashSize ) + sizeofObject( hashSize ) + \
sizeofInteger( certInfoPtr->cCertCert->serialNumber,
certInfoPtr->cCertCert->serialNumberLength ) );
writeAlgoID( stream, CRYPT_ALGO_SHA1 );
writeOctetString( stream, hashBuffer, hashSize, DEFAULT_TAG );
writeOctetString( stream, issuerKeyHash, issuerKeyHashLength,
DEFAULT_TAG );
return( writeInteger( stream, certInfoPtr->cCertCert->serialNumber,
certInfoPtr->cCertCert->serialNumberLength,
DEFAULT_TAG ) );
}
/* Sanitise certificate attributes based on a user-supplied template. This
is used to prevent a user from supplying potentially dangerous attributes
in a certificate 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 certificate 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 */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int sanitiseCertAttributes( INOUT CERT_INFO *certInfoPtr,
IN_OPT const ATTRIBUTE_LIST *templateListPtr )
{
const ATTRIBUTE_LIST *attributeListCursor;
int iterationCount;
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
assert( templateListPtr == NULL || \
( isReadPtr( templateListPtr, sizeof( ATTRIBUTE_LIST ) ) ) );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -