📄 certsig.c
字号:
/****************************************************************************
* *
* Certificate Signing/Checking Routines *
* Copyright Peter Gutmann 1997-2001 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL ) || defined( INC_CHILD )
#include "asn1.h"
#include "cert.h"
#else
#include "keymgmt/asn1.h"
#include "keymgmt/cert.h"
#endif /* Compiler-specific includes */
/* Prototypes for functions in lib_sign.c */
int createX509signature( void *signedObject, int *signedObjectLength,
const void *object, const int objectLength,
CRYPT_CONTEXT signContext,
const CRYPT_ALGO hashAlgo );
int checkX509signature( const void *signedObject, const int signedObjectLength,
void **object, int *objectLength,
CRYPT_CONTEXT sigCheckContext );
/****************************************************************************
* *
* Certificate Signing Functions *
* *
****************************************************************************/
/* Sign a certificate object */
int signCert( CERT_INFO *certInfoPtr, const CRYPT_CONTEXT signContext )
{
CERT_INFO *issuerCertInfoPtr = NULL;
STREAM stream;
BOOLEAN issuerCertPresent = FALSE, isCertificate = FALSE;
BOOLEAN nonSigningKey = FALSE;
BYTE certObjectBuffer[ 1024 ], *certObjectPtr = certObjectBuffer;
int ( *writeCertObjectFunction )( STREAM *stream, CERT_INFO *subjectCertInfoPtr,
const CERT_INFO *issuerCertInfoPtr,
const CRYPT_CONTEXT iIssuerCryptContext );
void *signedCertObject;
const time_t currentTime = time( NULL );
int certObjectLength, signedCertObjectLength, status;
/* If it's a non-signing key we have to create a special format of cert
request which isn't signed but contains an indication that the private
key POP will be performed by out-of-band means. We have to check for
the signContext being absent to handle OCSP requests for which the
signature is optional so there may be no signing key present */
if( signContext == CRYPT_UNUSED || \
cryptStatusError( krnlSendMessage( signContext, RESOURCE_IMESSAGE_CHECK,
NULL, RESOURCE_MESSAGE_CHECK_PKC_SIGN ) ) )
nonSigningKey = TRUE;
/* Set up type and version information as appropriate. We only handle
certificates at this point, other objects have versions which are
either explicitly determined (OCSP, setting certain attributes forces
use of v1 or v2) or implicitly determined when the object is finalised
for writing (for example CRLs, where the presence of extensions,
either added directly or copied from the signing cert, creates a v2
CRL). The remaining object types only have a single version */
if( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN )
{
int createV3cert;
isCertificate = TRUE;
krnlSendMessage( certInfoPtr->ownerHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE, &createV3cert,
CRYPT_OPTION_CERT_CREATEV3CERT );
certInfoPtr->version = \
( createV3cert || certInfoPtr->attributes != NULL ) ? 3 : 1;
}
/* Obtain the issuer certificate from the private key if necessary */
if( isCertificate || certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST && \
signContext != CRYPT_UNUSED ) || \
certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE )
{
/* If it's a self-signed cert, 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( signContext,
RESOURCE_IMESSAGE_GETDEPENDENT, &dataOnlyCert,
OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( status ) )
return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
CRYPT_ARGERROR_VALUE : status );
getCheckInternalResource( dataOnlyCert, issuerCertInfoPtr,
OBJECT_TYPE_CERTIFICATE );
issuerCertPresent = TRUE;
}
/* Make sure the key associated with the issuer cert is valid for
cert/CRL signing: We need a key+complete certificate (unless we're
creating a self-signed cert), and the cert has to allow the key to
be used for cert/CRL signing, unless we're signing an OCSP
response in which case the choose-your-own-signing-semantics in
the RFC don't really allow much in the way of checking */
if( ( issuerCertInfoPtr->type != CRYPT_CERTTYPE_CERTIFICATE && \
issuerCertInfoPtr->type != CRYPT_CERTTYPE_CERTCHAIN ) || \
( issuerCertPresent && issuerCertInfoPtr->certificate == NULL ) )
status = CRYPT_ARGERROR_VALUE;
else
if( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST )
status = checkCertUsage( issuerCertInfoPtr,
CRYPT_KEYUSAGE_DIGITALSIGNATURE | CRYPT_KEYUSAGE_NONREPUDIATION,
RESOURCE_MESSAGE_CHECK_PKC_SIGN, &certInfoPtr->errorLocus,
&certInfoPtr->errorType );
else
if( certInfoPtr->type != CRYPT_CERTTYPE_OCSP_RESPONSE )
{
status = checkCertUsage( issuerCertInfoPtr, ( isCertificate ) ? \
CRYPT_KEYUSAGE_KEYCERTSIGN : CRYPT_KEYUSAGE_CRLSIGN,
RESOURCE_MESSAGE_CHECK_CA, &certInfoPtr->errorLocus,
&certInfoPtr->errorType );
if( cryptStatusError( status ) && \
certInfoPtr->errorType == CRYPT_ERRTYPE_CONSTRAINT )
/* If there was a constraint problem, it's something
in the issuer's cert rather than the cert being
signed so we have to change the error type
accordingly. What's reported isn't striclty
accurate since the locus is in the issuer rather
than subject cert, but it's the best we can do */
certInfoPtr->errorType = CRYPT_ERRTYPE_ISSUERCONSTRAINT;
}
if( cryptStatusError( status ) )
{
if( issuerCertPresent )
unlockResource( issuerCertInfoPtr );
return( status );
}
}
/* If it's a certificate chain, copy over the signing cert and order the
certificates in the chain from the current one up to the root */
if( certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN )
{
/* If there's a chain of certs present (for example from a previous
signing attempt which wasn't completed due to an error), free
them */
if( certInfoPtr->certChainEnd )
{
int i;
for( i = 0; i < certInfoPtr->certChainEnd; i++ )
krnlSendNotifier( certInfoPtr->certChain[ i ],
RESOURCE_IMESSAGE_DECREFCOUNT );
certInfoPtr->certChainEnd = 0;
}
/* If it's a self-signed cert, it must be the only cert in the chain
(creating a chain like this doesn't make much sense, but we handle
it anyway) */
if( certInfoPtr->flags & CERT_FLAG_SELFSIGNED )
{
if( certInfoPtr->certChainEnd )
{
setErrorInfo( certInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
CRYPT_ERRTYPE_ATTR_PRESENT );
return( CRYPT_ERROR_INVALID );
}
}
else
{
/* Copy the cert chain into the cert to be signed */
status = copyCertChain( certInfoPtr, signContext );
if( cryptStatusError( status ) )
return( status );
}
}
/* 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 when
the data is encoded */
if( ( isCertificate || certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE ) && \
!certInfoPtr->startTime )
certInfoPtr->startTime = currentTime;
if( isCertificate && !certInfoPtr->endTime )
{
int validity;
krnlSendMessage( certInfoPtr->ownerHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE, &validity,
CRYPT_OPTION_CERT_VALIDITY );
certInfoPtr->endTime = certInfoPtr->startTime + \
( ( time_t ) validity * 86400L );
}
if( certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE )
{
if( !certInfoPtr->endTime )
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;
krnlSendMessage( certInfoPtr->ownerHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE, &updateInterval,
CRYPT_OPTION_CERT_UPDATEINTERVAL );
certInfoPtr->endTime = certInfoPtr->startTime + \
( ( time_t ) updateInterval * 86400L );
}
if( !certInfoPtr->revocationTime )
certInfoPtr->revocationTime = currentTime;
}
/* If it's a certificate, set up the certificate serial number. 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 signed by the CA. Because
of this, we just use a 64-bit nonce */
if( isCertificate )
{
BYTE *dataPtr;
/* Allocate storage for the value and copy it in, clearing the high
bit to provide a constant-length ASN.1 encoded value */
if( ( dataPtr = malloc( 8 ) ) == NULL )
{
if( issuerCertPresent )
unlockResource( issuerCertInfoPtr );
return( CRYPT_ERROR_MEMORY );
}
if( certInfoPtr->serialNumber != NULL )
free( certInfoPtr->serialNumber );
getNonce( dataPtr, 8 );
dataPtr[ 0 ] &= 0x7F;
certInfoPtr->serialNumber = dataPtr;
certInfoPtr->serialNumberLength = 8;
}
/* Select the function to use to write the certificate object to be
signed */
switch( certInfoPtr->type )
{
case CRYPT_CERTTYPE_CERTIFICATE:
case CRYPT_CERTTYPE_CERTCHAIN:
writeCertObjectFunction = writeCertInfo;
break;
case CRYPT_CERTTYPE_ATTRIBUTE_CERT:
writeCertObjectFunction = writeAttributeCertInfo;
break;
case CRYPT_CERTTYPE_CERTREQUEST:
writeCertObjectFunction = writeCertRequestInfo;
break;
case CRYPT_CERTTYPE_REQUEST_CERT:
writeCertObjectFunction = writeCRMFRequestInfo;
break;
case CRYPT_CERTTYPE_REQUEST_REVOCATION:
writeCertObjectFunction = writeRevRequestInfo;
break;
case CRYPT_CERTTYPE_CRL:
writeCertObjectFunction = writeCRLInfo;
break;
case CRYPT_CERTTYPE_OCSP_REQUEST:
writeCertObjectFunction = writeOCSPRequestInfo;
break;
case CRYPT_CERTTYPE_OCSP_RESPONSE:
writeCertObjectFunction = writeOCSPResponseInfo;
break;
case CRYPT_CERTTYPE_PKIUSER:
writeCertObjectFunction = writePKIUserInfo;
break;
default:
assert( NOTREACHED );
}
/* Determine how big the encoded certificate information will be,
allocate memory for it and the full signed certificate, and write the
encoded certificate information */
sMemOpen( &stream, NULL, 0 );
status = writeCertObjectFunction( &stream, certInfoPtr, issuerCertInfoPtr,
signContext );
certObjectLength = ( int ) stell( &stream );
sMemClose( &stream );
if( cryptStatusError( status ) )
{
if( issuerCertPresent )
unlockResource( issuerCertInfoPtr );
return( status );
}
if( ( certObjectLength > 1024 && \
( certObjectPtr = malloc( certObjectLength ) ) == NULL ) || \
( signedCertObject = malloc( certObjectLength + 1024 ) ) == NULL )
{
if( certObjectPtr != NULL )
free( certObjectPtr );
if( issuerCertPresent )
unlockResource( issuerCertInfoPtr );
return( CRYPT_ERROR_MEMORY );
}
sMemOpen( &stream, certObjectPtr, certObjectLength );
status = writeCertObjectFunction( &stream, certInfoPtr, issuerCertInfoPtr,
signContext );
assert( certObjectLength == stream.bufPos );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -