📄 write.c
字号:
REQUIRES( setActions >= PRE_SET_NONE && \
setActions <= PRE_SET_FLAG_MAX );
REQUIRES( checkActions >= PRE_CHECK_NONE && \
checkActions <= PRE_CHECK_FLAG_MAX );
REQUIRES( flags == PRE_FLAG_NONE || \
flags == PRE_FLAG_DN_IN_ISSUERCERT );
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
/* Correlate flags with pointers being null/nonnull */
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
/* Make sure that everything is in order. Some of the checks depend on
data that isn't set up yet, so first perform all of the setup actions
that add default and issuer-contributed attributes, and then perform
all of the checks */
if( setActions & PRE_SET_STANDARDATTR )
{
/* If it's a >= v3 certificate add the standard X.509v3 extensions
if these aren't already present */
if( subjectCertInfoPtr->version >= 3 )
{
status = addStandardExtensions( subjectCertInfoPtr );
if( cryptStatusError( status ) )
return( status );
}
}
if( setActions & PRE_SET_ISSUERATTR )
{
/* Copy any required extensions from the issuer to the subject
certificate if necessary */
if( !( subjectCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) )
{
status = copyIssuerAttributes( &subjectCertInfoPtr->attributes,
issuerCertInfoPtr->attributes,
subjectCertInfoPtr->type,
&subjectCertInfoPtr->errorLocus,
&subjectCertInfoPtr->errorType );
if( cryptStatusError( status ) )
return( status );
}
}
if( setActions & PRE_SET_ISSUERDN )
{
/* Copy the issuer DN if this isn't already present */
if( subjectCertInfoPtr->issuerName == NULL )
{
status = copyDN( &subjectCertInfoPtr->issuerName,
issuerCertInfoPtr->subjectName );
if( cryptStatusError( status ) )
return( status );
}
}
if( setActions & PRE_SET_VALIDITYPERIOD )
{
/* Constrain the subject validity period to be within the issuer
validity period */
if( subjectCertInfoPtr->startTime < issuerCertInfoPtr->startTime )
subjectCertInfoPtr->startTime = issuerCertInfoPtr->startTime;
if( subjectCertInfoPtr->endTime > issuerCertInfoPtr->endTime )
subjectCertInfoPtr->endTime = issuerCertInfoPtr->endTime;
}
if( setActions & PRE_SET_VALINFO )
{
/* If it's an RTCS response, prepare the certificate status list
entries prior to encoding them */
status = prepareValidityEntries( subjectCertInfoPtr->cCertVal->validityInfo,
&subjectCertInfoPtr->cCertVal->currentValidity,
&subjectCertInfoPtr->errorLocus,
&subjectCertInfoPtr->errorType );
if( cryptStatusError( status ) )
return( status );
}
if( setActions & PRE_SET_REVINFO )
{
REVOCATION_INFO *revocationErrorEntry;
const BOOLEAN isCrlEntry = checkActions ? FALSE : TRUE;
/* If it's a CRL or OCSP response, prepare the revocation list
entries prior to encoding them */
status = prepareRevocationEntries( subjectCertInfoPtr->cCertRev->revocations,
subjectCertInfoPtr->cCertRev->revocationTime,
&revocationErrorEntry, isCrlEntry,
&subjectCertInfoPtr->errorLocus,
&subjectCertInfoPtr->errorType );
if( cryptStatusError( status ) )
{
/* If there was an error and we're processing an entire
revocation list, select the entry that caused the problem */
if( !isCrlEntry )
{
subjectCertInfoPtr->cCertRev->currentRevocation = \
revocationErrorEntry;
}
return( status );
}
}
/* Now that everything's set up, check that the object is reading for
encoding */
if( checkActions & PRE_CHECK_SPKI )
{
/* Make sure that there's public-key info present */
if( subjectCertInfoPtr->publicKeyInfo == NULL )
{
setErrorInfo( subjectCertInfoPtr,
CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
}
if( checkActions & PRE_CHECK_DN )
{
/* Make sure that there's a full DN present */
status = checkDN( subjectCertInfoPtr->subjectName, TRUE, FALSE,
&subjectCertInfoPtr->errorLocus,
&subjectCertInfoPtr->errorType );
if( cryptStatusError( status ) )
{
/* In some very special cases an empty DN is permitted, so we
only return an error if this really isn't allowed */
if( status != CRYPT_ERROR_NOTINITED || \
!checkEmptyDnOK( subjectCertInfoPtr ) )
return( status );
}
}
if( checkActions & PRE_CHECK_DN_PARTIAL )
{
/* Make sure that there's at least a partial DN present (some CA's
will fill the remainder themselves) */
status = checkDN( subjectCertInfoPtr->subjectName, TRUE, TRUE,
&subjectCertInfoPtr->errorLocus,
&subjectCertInfoPtr->errorType );
if( cryptStatusError( status ) )
return( status );
}
if( checkActions & PRE_CHECK_ISSUERDN )
{
if( flags & PRE_FLAG_DN_IN_ISSUERCERT )
{
if( issuerCertInfoPtr == NULL || \
issuerCertInfoPtr->subjectDNptr == NULL || \
issuerCertInfoPtr->subjectDNsize < 1 )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_ISSUERNAME,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
}
else
{
/* The issuer DN can be present either in pre-encoded form (if
it was copied from an issuer certificate) or as a full DN (if
it's a self-signed certificate), so we check for the presence
of either */
if( ( subjectCertInfoPtr->issuerName == NULL ) &&
( subjectCertInfoPtr->issuerDNptr == NULL || \
subjectCertInfoPtr->issuerDNsize < 1 ) )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_ISSUERNAME,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
}
}
if( checkActions & PRE_CHECK_ISSUERCERTDN )
{
/* If it's a CRL, compare the revoked certificate issuer DN and
signer DN to make sure that we're not trying to revoke someone
else's certificates, and prepare the revocation entries */
if( !compareDN( subjectCertInfoPtr->issuerName,
issuerCertInfoPtr->subjectName, FALSE ) )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_ISSUERNAME,
CRYPT_ERRTYPE_ATTR_VALUE );
return( CRYPT_ERROR_INVALID );
}
}
if( checkActions & PRE_CHECK_NONSELFSIGNED_DN )
{
/* If we're creating a non-self-signed certificate check whether the
subject's DN is the same as the issuer's DN. If this is the
case then the resulting object would appear to be self-signed so
we disallow it */
if( compareDN( issuerCertInfoPtr->subjectName,
subjectCertInfoPtr->subjectName, FALSE ) )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_SUBJECTNAME,
CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_NOTINITED );
}
}
if( checkActions & PRE_CHECK_SERIALNO )
{
if( subjectCertInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION )
{
if( subjectCertInfoPtr->cCertReq->serialNumberLength <= 0 )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_SERIALNUMBER,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
}
else
{
if( subjectCertInfoPtr->cCertCert->serialNumberLength <= 0 )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_SERIALNUMBER,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
}
}
if( checkActions & PRE_CHECK_VALENTRIES )
{
if( subjectCertInfoPtr->cCertVal->validityInfo == NULL )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
}
if( checkActions & PRE_CHECK_REVENTRIES )
{
if( subjectCertInfoPtr->cCertRev->revocations == NULL )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
}
/* Now that we've set up the attributes, perform the remainder of the
checks. Because RTCS is a CMS standard rather than PKIX, the RTCS
attributes are CMS rather than certificate attributes */
if( subjectCertInfoPtr->attributes != NULL )
{
status = checkAttributes( ( subjectCertInfoPtr->type == \
CRYPT_CERTTYPE_RTCS_REQUEST ) ? \
ATTRIBUTE_CMS : ATTRIBUTE_CERTIFICATE,
subjectCertInfoPtr->attributes,
&subjectCertInfoPtr->errorLocus,
&subjectCertInfoPtr->errorType );
if( cryptStatusError( status ) )
return( status );
}
status = checkCert( subjectCertInfoPtr, issuerCertInfoPtr, FALSE,
&subjectCertInfoPtr->errorLocus,
&subjectCertInfoPtr->errorType );
if( cryptStatusError( status ) )
return( status );
/* If it's a certificate or certificate chain remember that it's been
checked at full compliance level. This short-circuits the need to
perform excessive levels of checking if the caller wants to re-check
it after it's been signed */
if( subjectCertInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
subjectCertInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN )
{
subjectCertInfoPtr->cCertCert->maxCheckLevel = \
CRYPT_COMPLIANCELEVEL_PKIX_FULL;
}
return( status );
}
/****************************************************************************
* *
* Write a Certificate Object *
* *
****************************************************************************/
/* Write certificate information:
CertificateInfo ::= SEQUENCE {
version [ 0 ] EXPLICIT INTEGER DEFAULT(0),
serialNumber INTEGER,
signature AlgorithmIdentifier,
issuer Name
validity Validity,
subject Name,
subjectPublicKeyInfo SubjectPublicKeyInfo,
extensions [ 3 ] Extensions OPTIONAL
} */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int writeCertInfo( INOUT STREAM *stream,
INOUT CERT_INFO *subjectCertInfoPtr,
const CERT_INFO *issuerCertInfoPtr,
IN_HANDLE const CRYPT_CONTEXT iIssuerCryptContext )
{
const CERT_CERT_INFO *certCertInfo = subjectCertInfoPtr->cCertCert;
const int algoIdInfoSize = \
sizeofContextAlgoID( iIssuerCryptContext, certCertInfo->hashAlgo );
int length, extensionSize, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
assert( isReadPtr( issuerCertInfoPtr, sizeof( CERT_INFO ) ) );
REQUIRES( isHandleRangeValid( iIssuerCryptContext ) );
if( cryptStatusError( algoIdInfoSize ) )
return( algoIdInfoSize );
/* Perform any necessary pre-encoding steps */
if( sIsNullStream( stream ) )
{
status = preEncodeCertificate( subjectCertInfoPtr, issuerCertInfoPtr,
PRE_SET_STANDARDATTR | PRE_SET_ISSUERATTR | \
PRE_SET_ISSUERDN | PRE_SET_VALIDITYPERIOD,
PRE_CHECK_SPKI | PRE_CHECK_DN | \
PRE_CHECK_ISSUERDN | PRE_CHECK_SERIALNO | \
( ( subjectCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) ? \
0 : PRE_CHECK_NONSELFSIGNED_DN ),
( issuerCertInfoPtr->subjectDNptr != NULL ) ? \
PRE_FLAG_DN_IN_ISSUERCERT : PRE_FLAG_NONE );
if( cryptStatusError( status ) )
return( status );
}
/* Determine how the issuer name will be encoded */
subjectCertInfoPtr->issuerDNsize = \
( issuerCertInfoPtr->subjectDNptr != NULL ) ? \
issuerCertInfoPtr->subjectDNsize : \
sizeofDN( subjectCertInfoPtr->issuerName );
subjectCertInfoPtr->subjectDNsize = \
sizeofDN( subjectCertInfoPtr->subjectName );
/* Determine the size of the certificate information */
extensionSize = sizeofAttributes( subjectCertInfoPtr->attributes );
if( cryptStatusError( extensionSize ) )
return( extensionSize );
length = sizeofInteger( certCertInfo->serialNumber,
certCertInfo->serialNumberLength ) + \
algoIdInfoSize + \
subjectCertInfoPtr->issuerDNsize + \
sizeofObject( sizeofUTCTime() * 2 ) + \
subjectCertInfoPtr->subjectDNsize + \
subjectCertInfoPtr->publicKeyInfoSize;
if( extensionSize > 0 )
{
length += sizeofObject( sizeofShortInteger( X509VERSION_3 ) ) + \
sizeofObject( sizeofObject( extensionSize ) );
}
/* Write the outer SEQUENCE wrapper */
writeSequence( stream, length );
/* If there are extensions present, mark this as a v3 certificate */
if( extensionSize > 0 )
{
writeConstructed( stream, sizeofShortInteger( X509VERSION_3 ),
CTAG_CE_VERSION );
writeShortInteger( stream, X509VERSION_3, DEFAULT_TAG );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -