📄 certcomp.c
字号:
if( caCertInfoPtr->type != CRYPT_CERTTYPE_CERTIFICATE )
status = CRYPT_ARGERROR_NUM1;
else
if( caCertInfoPtr->certificate == NULL )
status = CRYPT_ERROR_NOTINITED; /* Must be ready for use */
if( cryptStatusError( status ) )
unlockResourceExit( caCertInfoPtr, status );
/* Make sure it really is a CA cert, which means it either has to
be self-signed or have the basicConstraints CA field set */
if( !( caCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) )
{
ATTRIBUTE_LIST *attributeListPtr;
attributeListPtr = findAttributeField( caCertInfoPtr->attributes,
CRYPT_CERTINFO_CA, CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr == NULL || !attributeListPtr->value )
{
setErrorInfo( certInfoPtr, CRYPT_CERTINFO_CA,
CRYPT_ERRTYPE_ATTR_VALUE );
return( CRYPT_ERROR_INVALID );
}
}
/* Dig down into the encoded cert to find the bits of key which we
need to hash and hash them. We store the result as the cert hash,
which is safe because it isn't used for an OCSP request so it
can't be accessed externally */
sMemConnect( &stream, caCertInfoPtr->certificate,
caCertInfoPtr->certificateSize );
readSequence( &stream, NULL ); /* Outer wrapper */
readSequence( &stream, NULL ); /* Inner wrapper */
if( peekTag( &stream ) == MAKE_CTAG( 0 ) )
readUniversal( &stream ); /* Version */
readUniversal( &stream ); /* Serial number */
readUniversal( &stream ); /* Sig.algo */
readUniversal( &stream ); /* Issuer DN */
readUniversal( &stream ); /* Validity */
readUniversal( &stream ); /* Subject DN */
readSequence( &stream, NULL ); /* SPKI wrapper */
readUniversal( &stream ); /* SPKI AlgoID */
status = readBitStringHole( &stream, &length, DEFAULT_TAG );
if( cryptStatusError( status ) )/* BIT STRING wrapper */
{
/* There's a problem in the format of the CA certificate */
setErrorInfo( certInfoPtr, CRYPT_CERTINFO_CACERTIFICATE,
CRYPT_ERRTYPE_ATTR_VALUE );
unlockResourceExit( caCertInfoPtr, CRYPT_ERROR_INVALID );
}
hashFunction( NULL, certInfoPtr->certHash, sMemBufPtr( &stream ),
length, HASH_ALL );
certInfoPtr->certHashSet = TRUE;
assert( sGetStatus( &stream ) == CRYPT_OK );
sMemDisconnect( &stream );
/* If the cert hash is set, the user must want OCSPv1 IDs rather than
v2 IDs so we set the version info accordingly */
certInfoPtr->version = 1;
unlockResourceExit( caCertInfoPtr, status );
}
/* If it's PKI user info, set or modify data in a request based on the
user info */
if( certInfoType == CRYPT_IATTRIBUTE_PKIUSERINFO )
{
CRYPT_CERTIFICATE pkiUserInfo = *( ( CRYPT_HANDLE * ) certInfo );
CERT_INFO *pkiUserInfoPtr;
char commonName[ CRYPT_MAX_TEXTSIZE ];
int commonNameLength;
/* Make sure we've been passed PKI user info ready for use */
getCheckInternalResource( pkiUserInfo, pkiUserInfoPtr,
OBJECT_TYPE_CERTIFICATE );
if( pkiUserInfoPtr->type != CRYPT_CERTTYPE_PKIUSER )
status = CRYPT_ARGERROR_NUM1;
else
if( pkiUserInfoPtr->certificate == NULL )
status = CRYPT_ERROR_NOTINITED; /* Must be ready for use */
if( cryptStatusError( status ) )
unlockResourceExit( pkiUserInfoPtr, status );
/* If there's no DN present in the request, try and fill it in from
the CA-supplied PKI user info */
if( certInfoPtr->subjectName == NULL )
{
/* If neither the request nor the PKI user info has a DN present,
we can't continue */
if( pkiUserInfoPtr->subjectName == NULL )
unlockResourceExit( pkiUserInfoPtr, CRYPT_ERROR_NOTINITED );
/* There's no DN present in the request, it's been supplied by
the CA in the PKI user info, copy over the DN and its encoded
form from the PKI user info */
status = copyDN( &certInfoPtr->subjectName,
pkiUserInfoPtr->subjectName );
if( cryptStatusOK( status ) )
{
if( ( certInfoPtr->subjectDNdata = \
malloc( pkiUserInfoPtr->subjectDNsize ) ) == NULL )
{
deleteDN( &certInfoPtr->subjectName );
unlockResourceExit( certInfoPtr, CRYPT_ERROR_MEMORY );
}
memcpy( certInfoPtr->subjectDNdata, pkiUserInfoPtr->subjectDNptr,
pkiUserInfoPtr->subjectDNsize );
certInfoPtr->subjectDNptr = certInfoPtr->subjectDNdata;
certInfoPtr->subjectDNsize = pkiUserInfoPtr->subjectDNsize;
}
unlockResourceExit( pkiUserInfoPtr, status );
}
/* If there's no PKI user DN present which might conflict with the
one in the request, we're done */
if( pkiUserInfoPtr->subjectName == NULL )
unlockResourceExit( pkiUserInfoPtr, CRYPT_OK );
/* There's both a request DN and PKI user DN present. If the request
contains only a CN, combine it with the PKI user DN and update the
request */
status = getDNComponentValue( certInfoPtr->subjectName,
CRYPT_CERTINFO_COMMONNAME, commonName,
&commonNameLength, CRYPT_MAX_TEXTSIZE );
if( cryptStatusOK( status ) )
{
void *tempDN = NULL;
BOOLEAN isCommonNameDN;
/* Check whether the request DN contains only a CN. There's no
easy way to do this directly, the only way we can do it is by
creating a temporary DN consisting of only the CN and
comparing it to the request DN. We use sizeofDN() rather than
compareDN() since it's much faster than a full DN comparison,
this is safe because we know that both contain at least the
same CN so any size mismatch indicates a DN value mismatch */
status = insertDNComponent( &tempDN, CRYPT_CERTINFO_COMMONNAME,
commonName, commonNameLength,
&certInfoPtr->errorType );
if( cryptStatusError( status ) )
unlockResourceExit( pkiUserInfoPtr, status );
isCommonNameDN = sizeofDN( certInfoPtr->subjectName ) == \
sizeofDN( tempDN );
deleteDN( &tempDN );
/* If the two match, the request DN consists of only a CN,
append it to the PKI user DN */
if( isCommonNameDN )
{
STREAM stream;
void *tempDNdata;
int tempDNsize;
/* Copy the DN template, append the user-supplied CN, and
allocate room for the encoded form */
status = copyDN( &tempDN, pkiUserInfoPtr->subjectName );
unlockResource( pkiUserInfoPtr );
if( cryptStatusError( status ) )
return( status );
status = insertDNComponent( &tempDN, CRYPT_CERTINFO_COMMONNAME,
commonName, commonNameLength,
&certInfoPtr->errorType );
if( cryptStatusOK( status ) )
{
tempDNsize = sizeofDN( tempDN );
if( ( tempDNdata = malloc( tempDNsize ) ) == NULL )
status = CRYPT_ERROR_MEMORY;
}
if( cryptStatusError( status ) )
{
deleteDN( &tempDN );
return( status );
}
/* Everything went OK, replace the existing DN with the new
one and set up the encoded form */
deleteDN( &certInfoPtr->subjectName );
certInfoPtr->subjectName = tempDN;
sMemOpen( &stream, tempDNdata, tempDNsize );
writeDN( &stream, tempDN, DEFAULT_TAG );
sMemDisconnect( &stream );
certInfoPtr->subjectDNdata = \
certInfoPtr->subjectDNptr = tempDNdata;
certInfoPtr->subjectDNsize = tempDNsize;
return( status );
}
}
/* There are full DNs present in both objects, make sure they're the
same */
if( !compareDN( certInfoPtr->subjectName,
pkiUserInfoPtr->subjectName, FALSE ) )
status = CRYPT_ERROR_INVALID;
unlockResourceExit( pkiUserInfoPtr, status );
}
/* If it's a GeneralName or DN selection command, set up the selection */
if( isGeneralNameSelectionComponent( certInfoType ) || \
isDNSelectionComponent( certInfoType ) )
{
if( *( ( int * ) certInfo ) != CRYPT_UNUSED )
return( CRYPT_ARGERROR_NUM1 );
/* If it's a built-in DN, it's a straight selection */
if( certInfoType == CRYPT_CERTINFO_SUBJECTNAME || \
certInfoType == CRYPT_CERTINFO_ISSUERNAME )
return( selectDN( certInfoPtr, certInfoType, SELECT_SELECT ) );
/* It's a GeneralName or a DN in a GeneralName, remember it. If
we're doing the selection for an initialised cert and we can't
find the entry, we return a not found error, however this isn't
an error for a non-initialised cert since we may be just
selecting the entry prior to initialising it */
if( selectGeneralName( certInfoPtr, certInfoType,
SELECT_SELECT ) == NULL && \
certInfoPtr->certificate != NULL )
return( CRYPT_ERROR_NOTFOUND );
return( CRYPT_OK );
}
/* If it's a GeneralName component, add it to the current GeneralName */
if( isGeneralNameComponent( certInfoType ) )
{
selectGeneralName( certInfoPtr, certInfoPtr->currentGeneralName,
SELECT_SELECT );
return( addAttributeField( &certInfoPtr->attributes,
certInfoPtr->currentGeneralName, certInfoType, certInfo,
certInfoLength, ATTR_FLAG_NONE, &certInfoPtr->errorLocus,
&certInfoPtr->errorType ) );
}
/* If it's a complete DN, set it */
if( certInfoType == CRYPT_CERTINFO_DN )
{
int status;
/* If there's already a DN set, we can't do anything else */
status = selectDN( certInfoPtr, CRYPT_ATTRIBUTE_NONE,
SELECT_INSTANTIATE_SET );
if( cryptStatusOK( status ) && *certInfoPtr->currentDNptr != NULL )
status = CRYPT_ERROR_INITED;
if( cryptStatusError( status ) )
return( status );
/* Read the entire DN from its string form into the selected DN */
return( readDNstring( certInfo, certInfoLength,
certInfoPtr->currentDNptr ) );
}
/* If it's a DN component, add it to the DN */
if( isDNComponent( certInfoType ) )
{
int status;
/* Add the string component to the DN */
status = selectDN( certInfoPtr, CRYPT_ATTRIBUTE_NONE,
SELECT_INSTANTIATE_SET );
if( cryptStatusOK( status ) )
status = insertDNComponent( certInfoPtr->currentDNptr,
certInfoType, certInfo, certInfoLength,
&certInfoPtr->errorType );
if( cryptStatusError( status ) && status != CRYPT_ERROR_MEMORY )
certInfoPtr->errorLocus = certInfoType;
return( status );
}
/* If it's time information, set it. We check to make sure the time
given isn't before 1993, the start date for X.509v2 (this is more of
a consistency check than any real requirement) and that we don't have
a negative validity period */
if( certInfoType == CRYPT_CERTINFO_VALIDFROM || \
certInfoType == CRYPT_CERTINFO_THISUPDATE )
{
time_t certTime = *( ( time_t * ) certInfo );
status = checkTime( certInfoPtr, certInfoType, certInfoPtr->startTime,
certTime, certInfoLength );
if( cryptStatusError( status ) )
return( status );
if( certInfoPtr->endTime && certTime >= certInfoPtr->endTime )
{
setErrorInfo( certInfoPtr,
( certInfoType == CRYPT_CERTINFO_VALIDFROM ) ? \
CRYPT_CERTINFO_VALIDTO : CRYPT_CERTINFO_NEXTUPDATE,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ARGERROR_STR1 );
}
certInfoPtr->startTime = certTime;
return( CRYPT_OK );
}
if( certInfoType == CRYPT_CERTINFO_VALIDTO || \
certInfoType == CRYPT_CERTINFO_NEXTUPDATE )
{
time_t certTime = *( ( time_t * ) certInfo );
status = checkTime( certInfoPtr, certInfoType, certInfoPtr->endTime,
certTime, certInfoLength );
if( cryptStatusError( status ) )
return( status );
if( certInfoPtr->startTime && certTime <= certInfoPtr->startTime )
{
setErrorInfo( certInfoPtr,
( certInfoType == CRYPT_CERTINFO_VALIDTO ) ? \
CRYPT_CERTINFO_VALIDFROM : CRYPT_CERTINFO_THISUPDATE,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ARGERROR_STR1 );
}
certInfoPtr->endTime = certTime;
return( CRYPT_OK );
}
if( certInfoType == CRYPT_CERTINFO_REVOCATIONDATE )
{
time_t certTime = *( ( time_t * ) certInfo ), *revocationTimePtr;
status = checkTime( certInfoPtr, certInfoType, certInfoPtr->startTime,
certTime, certInfoLength );
if( cryptStatusError( status ) )
return( status );
/* If there's a specific revoked cert selected, set its revocation
time, otherwise if there are revoked certs present set the first
certs revocation time otherwise set the default revocation time */
revocationTimePtr = ( certInfoPtr->currentRevocation != NULL ) ? \
&certInfoPtr->currentRevocation->revocationTime : \
( certInfoPtr->revocations != NULL ) ? \
&certInfoPtr->revocations->revocationTime : \
&certInfoPtr->revocationTime;
*revocationTimePtr = certTime;
return( CRYPT_OK );
}
/* If it's a generic string component, set it */
if( certInfoType == CRYPT_IATTRIBUTE_AUTHCERTID )
{
assert( certInfoLength == KEYID_SIZE );
memcpy( certInfoPtr->authCertID, certInfo, KEYID_SIZE );
return( CRYPT_OK );
}
/* If it's a known attribute, add it to the certificate */
if( ( certInfoType >= CRYPT_FIRST_EXTENSION && \
certInfoType <= CRYPT_LAST_EXTENSION ) || \
( certInfoType >= CRYPT_FIRST_CMS && \
certInfoType <= CRYPT_LAST_CMS ) )
{
/* If it's a CRL or OCSP per-entry attribute, add the attribute to
the currently selected entry unless it's a revocation request, in
which case it goes in with the main attributes */
if( isRevocationEntryComponent( certInfoType ) && \
certInfoPtr->type != CRYPT_CERTTYPE_REQUEST_REVOCATION )
{
if( certInfoPtr->currentRevocation == NULL )
return( CRYPT_ERROR_NOTFOUND );
return( addAttributeField( &certInfoPtr->currentRevocation->attributes,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -