📄 certsign.c
字号:
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
REQUIRES( iSignContext == CRYPT_UNUSED || \
isHandleRangeValid( iSignContext ) );
/* If it's some certificate variant or CRL/OCSP response and the various
timestamps haven't been set yet start them at the current time and
give them the default validity period or next update time if these
haven't been set. The time used is the local time, this is converted
to GMT when we write it to the certificate. Issues like validity
period nesting and checking for valid time periods are handled
elsewhere */
if( ( isCertificate || certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE ) && \
certInfoPtr->startTime <= MIN_TIME_VALUE )
{
/* If the time is screwed up we can't provide a signed indication
of the time */
if( currentTime <= MIN_TIME_VALUE )
{
setErrorInfo( certInfoPtr, CRYPT_CERTINFO_VALIDFROM,
CRYPT_ERRTYPE_ATTR_VALUE );
return( CRYPT_ERROR_NOTINITED );
}
certInfoPtr->startTime = currentTime;
}
if( isCertificate && certInfoPtr->endTime <= MIN_TIME_VALUE )
{
int validity;
status = krnlSendMessage( certInfoPtr->ownerHandle,
IMESSAGE_GETATTRIBUTE, &validity,
CRYPT_OPTION_CERT_VALIDITY );
if( cryptStatusError( status ) )
return( status );
certInfoPtr->endTime = certInfoPtr->startTime + \
( ( time_t ) validity * 86400L );
}
if( certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE )
{
if( certInfoPtr->endTime <= MIN_TIME_VALUE )
{
if( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE )
{
/* OCSP responses come directly from the certificate store
and represent an atomic (and ephemeral) snapshot of the
store state. Because of this the next-update time is
effectively immediately since the next snapshot could
provide a different response */
certInfoPtr->endTime = currentTime;
}
else
{
int updateInterval;
status = krnlSendMessage( certInfoPtr->ownerHandle,
IMESSAGE_GETATTRIBUTE, &updateInterval,
CRYPT_OPTION_CERT_UPDATEINTERVAL );
if( cryptStatusError( status ) )
return( status );
certInfoPtr->endTime = certInfoPtr->startTime + \
( ( time_t ) updateInterval * 86400L );
}
}
if( certInfoPtr->cCertRev->revocationTime <= MIN_TIME_VALUE )
certInfoPtr->cCertRev->revocationTime = currentTime;
}
return( CRYPT_OK );
}
/****************************************************************************
* *
* Signing Functions *
* *
****************************************************************************/
/* Pseudo-sign certificate information by writing the outer wrapper and
moving the object into the initialised state */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
static int pseudoSignCertificate( INOUT CERT_INFO *certInfoPtr,
INOUT_BUFFER_FIXED( signedCertObjectMaxLength ) \
void *signedCertObject,
IN_LENGTH_SHORT_MIN( 16 ) \
const int signedCertObjectMaxLength,
IN_BUFFER( certObjectLength ) \
const void *certObject,
IN_LENGTH_SHORT_MIN( 16 ) \
const int certObjectLength )
{
STREAM stream;
int signedCertObjectLength, status;
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
assert( isWritePtr( signedCertObject, signedCertObjectMaxLength ) );
assert( isReadPtr( certObject, certObjectLength ) );
REQUIRES( signedCertObjectMaxLength >= 16 && \
signedCertObjectMaxLength < MAX_INTLENGTH_SHORT );
REQUIRES( certObjectLength >= 16 && \
certObjectLength <= signedCertObjectMaxLength && \
certObjectLength < MAX_INTLENGTH_SHORT );
switch( certInfoPtr->type )
{
case CRYPT_CERTTYPE_OCSP_REQUEST:
case CRYPT_CERTTYPE_PKIUSER:
/* It's an unsigned OCSP request or PKI user info, write the
outer wrapper */
signedCertObjectLength = sizeofObject( certObjectLength );
ENSURES( signedCertObjectLength <= signedCertObjectMaxLength );
sMemOpen( &stream, signedCertObject, signedCertObjectLength );
writeSequence( &stream, certObjectLength );
status = swrite( &stream, certObject, certObjectLength );
ENSURES( cryptStatusOK( status ) );
sMemDisconnect( &stream );
if( certInfoPtr->type == CRYPT_CERTTYPE_PKIUSER )
{
status = recoverCertData( certInfoPtr,
CRYPT_CERTTYPE_PKIUSER,
signedCertObject,
signedCertObjectLength );
if( cryptStatusError( status ) )
return( status );
}
break;
case CRYPT_CERTTYPE_RTCS_REQUEST:
case CRYPT_CERTTYPE_RTCS_RESPONSE:
case CRYPT_CERTTYPE_OCSP_RESPONSE:
/* It's an RTCS request/response or OCSP response, it's already
in the form required */
signedCertObjectLength = certObjectLength;
ENSURES( signedCertObjectLength <= signedCertObjectMaxLength );
memcpy( signedCertObject, certObject, certObjectLength );
break;
case CRYPT_CERTTYPE_REQUEST_CERT:
{
const int dataSize = certObjectLength + \
sizeofObject( sizeofShortInteger( 0 ) );
ENSURES( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT );
/* It's an encryption-only key, wrap up the certificate data
with an indication that private key POP will be performed via
out-of-band means and remember where the encoded data
starts */
signedCertObjectLength = sizeofObject( dataSize );
ENSURES( signedCertObjectLength <= signedCertObjectMaxLength );
sMemOpen( &stream, signedCertObject, signedCertObjectLength );
writeSequence( &stream, dataSize );
swrite( &stream, certObject, certObjectLength );
writeConstructed( &stream, sizeofShortInteger( 0 ), 2 );
status = writeShortInteger( &stream, 0, 1 );
ENSURES( cryptStatusOK( status ) );
sMemDisconnect( &stream );
status = recoverCertData( certInfoPtr,
CRYPT_CERTTYPE_REQUEST_CERT,
signedCertObject,
signedCertObjectLength );
if( cryptStatusError( status ) )
return( status );
/* The pseudo-signature has been checked (since we just created
it), this also avoids nasty semantic problems with not-really-
signed CRMF requests with encryption-only keys */
certInfoPtr->flags |= CERT_FLAG_SELFSIGNED;
break;
}
case CRYPT_CERTTYPE_REQUEST_REVOCATION:
/* Revocation requests can't be signed so the (pseudo-)signed
data is just the object data */
signedCertObjectLength = certObjectLength;
ENSURES( signedCertObjectLength <= signedCertObjectMaxLength );
memcpy( signedCertObject, certObject, certObjectLength );
/* Since revocation requests can't be signed we mark them as
pseudo-signed to avoid any problems that might arise from
this */
certInfoPtr->flags |= CERT_FLAG_SELFSIGNED;
break;
default:
retIntError();
}
certInfoPtr->certificate = signedCertObject;
certInfoPtr->certificateSize = signedCertObjectLength;
/* The object is now (pseudo-)signed and initialised */
certInfoPtr->flags |= CERT_FLAG_SIGCHECKED;
if( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT )
{
/* If it's a CRMF request with POP done via out-of-band means we
got here via a standard signing action (except that the key was
an encryption-only key), don't change the object state since the
kernel will do this as the post-signing step */
return( CRYPT_OK );
}
return( krnlSendMessage( certInfoPtr->objectHandle,
IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_UNUSED,
CRYPT_IATTRIBUTE_INITIALISED ) );
}
/* Sign a certificate object */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int signCert( INOUT CERT_INFO *certInfoPtr,
IN_HANDLE_OPT const CRYPT_CONTEXT iSignContext )
{
CRYPT_ALGO_TYPE hashAlgo;
CERT_INFO *issuerCertInfoPtr = NULL;
STREAM stream;
WRITECERT_FUNCTION writeCertFunction;
const CRYPT_SIGNATURELEVEL_TYPE signatureLevel = \
( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST ) ? \
certInfoPtr->cCertRev->signatureLevel : \
CRYPT_SIGNATURELEVEL_NONE;
const BOOLEAN isCertificate = \
( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN ) ? TRUE : FALSE;
BOOLEAN issuerCertAcquired = FALSE, nonSigningKey = FALSE;
BYTE certObjectBuffer[ 1024 + 8 ], *certObjectPtr = certObjectBuffer;
void *signedCertObject;
int certObjectLength, signedCertObjectLength, signedCertAllocSize;
int extraDataLength = 0, complianceLevel, status;
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
REQUIRES( iSignContext == CRYPT_UNUSED || \
isHandleRangeValid( iSignContext ) );
REQUIRES( certInfoPtr->certificate == NULL );
/* Determine how much checking we need to perform */
status = krnlSendMessage( certInfoPtr->ownerHandle,
IMESSAGE_GETATTRIBUTE, &complianceLevel,
CRYPT_OPTION_CERT_COMPLIANCELEVEL );
if( cryptStatusError( status ) )
return( status );
/* If it's a non-signing key we have to create a special format of
certificate request that isn't signed but contains an indication that
the private key POP will be performed by out-of-band means. We also
have to check for the iSignContext being absent to handle OCSP
requests for which the signature is optional so there may be no
signing key present */
if( iSignContext == CRYPT_UNUSED || \
cryptStatusError( krnlSendMessage( iSignContext, IMESSAGE_CHECK,
NULL, MESSAGE_CHECK_PKC_SIGN ) ) )
nonSigningKey = TRUE;
/* Obtain the issuer certificate from the private key if necessary */
if( isCertificate || certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
( ( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST || \
certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE ) && \
!nonSigningKey ) )
{
/* If it's a self-signed certificate then the issuer is also the
subject */
if( certInfoPtr->flags & CERT_FLAG_SELFSIGNED )
issuerCertInfoPtr = certInfoPtr;
else
{
CRYPT_CERTIFICATE dataOnlyCert;
/* Get the data-only certificate from the context */
status = krnlSendMessage( iSignContext, IMESSAGE_GETDEPENDENT,
&dataOnlyCert, OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( status ) )
return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
CRYPT_ARGERROR_VALUE : status );
status = krnlAcquireObject( dataOnlyCert, OBJECT_TYPE_CERTIFICATE,
( void ** ) &issuerCertInfoPtr,
CRYPT_ARGERROR_VALUE );
if( cryptStatusError( status ) )
return( status );
issuerCertAcquired = TRUE;
}
/* Check the signing key */
status = checkSigningKey( certInfoPtr, issuerCertInfoPtr,
isCertificate, complianceLevel );
if( cryptStatusError( status ) )
{
if( issuerCertAcquired )
krnlReleaseObject( issuerCertInfoPtr->objectHandle );
return( status );
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -