📄 comp_set.c
字号:
HASHFUNCTION_ATOMIC hashFunctionAtomic;
STREAM stream;
void *dataPtr = DUMMY_INIT_PTR;
int length, status;
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
assert( isWritePtr( caCertInfoPtr, sizeof( CERT_INFO ) ) );
REQUIRES( caCertInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
caCertInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
REQUIRES( caCertInfoPtr->publicKeyInfo != NULL );
getHashAtomicParameters( CRYPT_ALGO_SHA1, &hashFunctionAtomic, NULL );
/* Dig down into the encoded key data to find the weird bits of key that
OCSP requires us to hash. We store the result as the certificate
hash, which is safe because it isn't used for an OCSP request so it
can't be accessed externally */
sMemConnect( &stream, caCertInfoPtr->publicKeyInfo,
caCertInfoPtr->publicKeyInfoSize );
readSequence( &stream, NULL ); /* Wrapper */
readUniversal( &stream ); /* AlgoID */
status = readBitStringHole( &stream, &length, 16, DEFAULT_TAG );
if( cryptStatusOK( status ) ) /* BIT STRING wrapper */
status = sMemGetDataBlock( &stream, &dataPtr, length );
if( cryptStatusError( status ) )
{
/* There's a problem with the format of the key */
assert( DEBUG_WARN );
setErrorInfo( certInfoPtr, CRYPT_CERTINFO_CACERTIFICATE,
CRYPT_ERRTYPE_ATTR_VALUE );
return( CRYPT_ERROR_INVALID );
}
hashFunctionAtomic( certInfoPtr->certHash, KEYID_SIZE, dataPtr, length );
certInfoPtr->certHashSet = TRUE;
sMemDisconnect( &stream );
return( CRYPT_OK );
}
/* Set or modify data in a certificate request based on the PKI user info */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int copyPkiUserAttributes( INOUT CERT_INFO *certInfoPtr,
INOUT ATTRIBUTE_LIST *pkiUserAttributes )
{
ATTRIBUTE_LIST *attributeListPtr;
int status;
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
assert( isWritePtr( pkiUserAttributes, sizeof( ATTRIBUTE_LIST ) ) );
/* There's one rather ugly special-case situation that we have to handle
which is when the user has submitted a PnP PKI request for a generic
signing certificate but their PKI user info indicates that they're
intended to be a CA user. The processing flow for this is as follows:
CMP: readRequestBody()
Read request into state=high certificate request object;
Add PKI user info to request;
ca_issue: caIssuerCert()
Add request to newly-created certificate object;
Sign certificate;
When augmenting the request with the PKI user info the incoming
request will contain a keyUsage of digitalSignature while the PKI
user info will contain a keyUsage of keyCertSign and/or crlSign. We
can't fix this up at the CMP level because the request is in the high
state and no changes to the attributes can be made (the PKI user info
is a special case that can added to an object in the high state but
which modifies attributes in it as if it were still in the low state).
To avoid the attribute conflict, if we find this situation in the
request/pkiUser combination we delete the keyUsage in the request to
allow it to be replaced by the pkiUser attributes. Hardcoding in
this special case isn't very elegant but it's the only way to make
the PnP PKI issue work without requiring that the user explicitly
specify that they want to be a CA, which makes it rather non-PnP */
attributeListPtr = findAttributeField( certInfoPtr->attributes,
CRYPT_CERTINFO_KEYUSAGE,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL && \
attributeListPtr->intValue == CRYPT_KEYUSAGE_DIGITALSIGNATURE )
{
const ATTRIBUTE_LIST *pkiAttributeListPtr = \
findAttributeField( pkiUserAttributes, CRYPT_CERTINFO_KEYUSAGE,
CRYPT_ATTRIBUTE_NONE );
if( pkiAttributeListPtr != NULL && \
( pkiAttributeListPtr->intValue & ( CRYPT_KEYUSAGE_KEYCERTSIGN | \
CRYPT_KEYUSAGE_CRLSIGN ) ) )
{
/* The certificate contains a digitalSignature keyUsage and the
PKI user info contains a CA usage, delete the digitalSignature
usage to make way for the CA usage */
deleteAttribute( &certInfoPtr->attributes,
&certInfoPtr->attributeCursor, attributeListPtr,
certInfoPtr->currentSelection.dnPtr );
}
}
/* Copy the attributes from the PKI user info into the certificate */
status = copyAttributes( &certInfoPtr->attributes, pkiUserAttributes,
&certInfoPtr->errorLocus,
&certInfoPtr->errorType );
if( cryptStatusError( status ) )
return( status );
/* The PKI user info contains an sKID that's used to uniquely identify
the user, this applies to the user info itself rather than the
certificate that'll be issued from it. Since this will have been
copied over alongside the other attributes we need to explicitly
delete it before we continue */
attributeListPtr = findAttributeField( certInfoPtr->attributes,
CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL )
{
deleteAttribute( &certInfoPtr->attributes,
&certInfoPtr->attributeCursor, attributeListPtr,
certInfoPtr->currentSelection.dnPtr );
}
return( CRYPT_OK );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int assemblePkiUserDN( INOUT CERT_INFO *certInfoPtr,
const void *pkiUserSubjectName,
IN_BUFFER( commonNameLength ) const void *commonName,
IN_LENGTH_SHORT const int commonNameLength )
{
STREAM stream;
void *tempDN = NULL, *tempDNdata;
int tempDNsize = DUMMY_INIT, status;
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
assert( isReadPtr( commonName, commonNameLength ) );
REQUIRES( pkiUserSubjectName != NULL );
REQUIRES( commonNameLength > 0 && \
commonNameLength < MAX_INTLENGTH_SHORT );
/* Copy the DN template, append the user-supplied CN, and allocate room
for the encoded form */
status = copyDN( &tempDN, pkiUserSubjectName );
if( cryptStatusError( status ) )
return( status );
status = insertDNComponent( &tempDN, CRYPT_CERTINFO_COMMONNAME,
commonName, commonNameLength,
&certInfoPtr->errorType );
if( cryptStatusOK( status ) )
status = tempDNsize = sizeofDN( tempDN );
if( cryptStatusError( status ) )
{
deleteDN( &tempDN );
return( status );
}
if( ( tempDNdata = clAlloc( "assemblePkiUserDN", tempDNsize ) ) == NULL )
{
deleteDN( &tempDN );
return( CRYPT_ERROR_MEMORY );
}
/* Replace the existing DN with the new one and set up the encoded
form */
deleteDN( &certInfoPtr->subjectName );
certInfoPtr->subjectName = tempDN;
sMemOpen( &stream, tempDNdata, tempDNsize );
status = writeDN( &stream, tempDN, DEFAULT_TAG );
ENSURES( cryptStatusOK( status ) );
sMemDisconnect( &stream );
certInfoPtr->subjectDNdata = certInfoPtr->subjectDNptr = tempDNdata;
certInfoPtr->subjectDNsize = tempDNsize;
return( CRYPT_OK );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int copyPkiUserInfo( INOUT CERT_INFO *certInfoPtr,
INOUT CERT_INFO *pkiUserInfoPtr )
{
char commonName[ CRYPT_MAX_TEXTSIZE + 8 ];
int commonNameLength, status;
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
assert( isWritePtr( pkiUserInfoPtr, sizeof( CERT_INFO ) ) );
REQUIRES( pkiUserInfoPtr->type == CRYPT_CERTTYPE_PKIUSER );
REQUIRES( pkiUserInfoPtr->certificate != NULL );
/* 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 )
return( CRYPT_ERROR_NOTINITED );
ENSURES( pkiUserInfoPtr->subjectDNptr != NULL );
/* 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 user info */
status = copyDN( &certInfoPtr->subjectName,
pkiUserInfoPtr->subjectName );
if( cryptStatusError( status ) )
return( status );
if( ( certInfoPtr->subjectDNdata = \
clAlloc( "copyPkiUserInfo",
pkiUserInfoPtr->subjectDNsize ) ) == NULL )
{
deleteDN( &certInfoPtr->subjectName );
return( CRYPT_ERROR_MEMORY );
}
memcpy( certInfoPtr->subjectDNdata, pkiUserInfoPtr->subjectDNptr,
pkiUserInfoPtr->subjectDNsize );
certInfoPtr->subjectDNptr = certInfoPtr->subjectDNdata;
certInfoPtr->subjectDNsize = pkiUserInfoPtr->subjectDNsize;
/* Copy any additional attributes across */
return( copyPkiUserAttributes( certInfoPtr,
pkiUserInfoPtr->attributes ) );
}
/* If there's no PKI user DN with the potential to conflict with the one
in the request present, copy any additional attributes across and
exit */
if( pkiUserInfoPtr->subjectName == NULL )
{
return( copyPkiUserAttributes( certInfoPtr,
pkiUserInfoPtr->attributes ) );
}
/* 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,
CRYPT_MAX_TEXTSIZE, &commonNameLength );
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 that we can do it is by
creating a temporary DN consisting of only the CN and comparing
it to the request DN */
status = insertDNComponent( &tempDN, CRYPT_CERTINFO_COMMONNAME,
commonName, commonNameLength,
&certInfoPtr->errorType );
if( cryptStatusError( status ) )
return( status );
isCommonNameDN = compareDN( certInfoPtr->subjectName,
tempDN, FALSE );
deleteDN( &tempDN );
/* If the request DN consists only of a CN, append it to the PKI
user DN */
if( isCommonNameDN )
{
status = assemblePkiUserDN( certInfoPtr,
pkiUserInfoPtr->subjectName,
commonName, commonNameLength );
if( cryptStatusError( status ) )
return( status );
/* Copy any additional attributes across */
return( copyPkiUserAttributes( certInfoPtr,
pkiUserInfoPtr->attributes ) );
}
}
/* There are full DNs present in both objects, make sure that they're
the same and copy any additional attributes across */
if( !compareDN( certInfoPtr->subjectName,
pkiUserInfoPtr->subjectName, FALSE ) )
return( CRYPT_ERROR_INVALID );
return( copyPkiUserAttributes( certInfoPtr,
pkiUserInfoPtr->attributes ) );
}
/****************************************************************************
* *
* Set Certificate Info *
* *
****************************************************************************/
/* Set XYZZY certificate info */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int setXyzzyInfo( INOUT CERT_INFO *certInfoPtr )
{
ATTRIBUTE_LIST *attributeListPtr;
const int keyUsage = CRYPT_KEYUSAGE_DIGITALSIGNATURE | \
CRYPT_KEYUSAGE_NONREPUDIATION | \
CRYPT_KEYUSAGE_KEYENCIPHERMENT | \
CRYPT_KEYUSAGE_KEYCERTSIGN | \
CRYPT_KEYUSAGE_CRLSIGN;
const time_t currentTime = getApproxTime();
int status;
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
/* Make sure that we haven't already set up this certificate as a XYZZY
certificate */
attributeListPtr = findAttributeField( certInfoPtr->attributes,
CRYPT_CERTINFO_CERTPOLICYID,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL && \
attributeListPtr->valueLength == sizeofOID( OID_CRYPTLIB_XYZZYCERT ) && \
!memcmp( attributeListPtr->value, OID_CRYPTLIB_XYZZYCERT,
attributeListPtr->valueLength ) )
{
setErrorInfo( certInfoPtr, CRYPT_CERTINFO_XYZZY,
CRYPT_ERRTYPE_ATTR_PRESENT );
return( CRYPT_ERROR_INITED );
}
/* Clear any existing attribute values before trying to set new ones.
We don't check the return values for these operations because
depending on whether a component is present or not we could get a
success or error status, and in any case any problem with deleting
a present component will be caught when we try and set the new value
further on */
certInfoPtr->startTime = certInfoPtr->endTime = 0;
( void ) deleteCertComponent( certInfoPtr, CRYPT_CERTINFO_KEYUSAGE );
( void ) deleteCertComponent( certInfoPtr,
CRYPT_CERTINFO_CERTIFICATEPOLICIES );
/* Give the certificate a 20-year expiry time, make it a self-signed CA
certificate with all key usage types enabled, and set the policy OID
to identify it as a XYZZY certificate */
certInfoPtr->startTime = currentTime;
certInfoPtr->endTime = certInfoPtr->startTime + ( 86400L * 365 * 20 );
certInfoPtr->flags |= CERT_FLAG_SELFSIGNED;
status = addCertComponent( certInfoPtr, CRYPT_CERTINFO_CA,
MESSAGE_VALUE_TRUE, CRYPT_UNUSED );
if( cryptStatusOK( status ) )
status = addCertComponent( certInfoPtr, CRYPT_CERTINFO_KEYUSAGE,
&keyUsage, CRYPT_UNUSED );
if( cryptStatusOK( status ) )
status = addCertComponent( certInfoPtr, CRYPT_CERTINFO_CERTPOLICYID,
OID_CRYPTLIB_XYZZYCERT,
sizeofOID( OID_CRYPTLIB_XYZZYCERT ) );
if( cryptStatusOK( status ) )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -