Ejemplo n.º 1
0
static int adjustPkiUserAttributes( INOUT CERT_INFO *certInfoPtr )
	{
	int status;

	assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );

	/* The SCEP protocol requires that the SCEP challenge password be placed 
	   in the PKCS #10 request instead of being included in the SCEP 
	   metadata.  This shouldn't have been copied across to the certificate 
	   request since the NOCOPY flag was set for the attribute, but to make 
	   absolutely certain we try and delete it anyway.  Since this could in 
	   theory be present in non-SCEP requests as well (the request-
	   processing code just knows about PKCS #10 requests as a whole, not 
	   requests from a SCEP source vs. requests not from a SCEP source), we 
	   make the delete unconditional */
	if( findAttributeField( certInfoPtr->attributes,
							CRYPT_CERTINFO_CHALLENGEPASSWORD, 
							CRYPT_ATTRIBUTE_NONE ) != NULL )
		{
		status = deleteCompleteAttribute( &certInfoPtr->attributes,
										  &certInfoPtr->attributeCursor, 
										  CRYPT_CERTINFO_CHALLENGEPASSWORD, 
										  certInfoPtr->currentSelection.dnPtr );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* The PKI user information contains an sKID that's used to uniquely 
	   identify the user, this applies to the user information 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 */
	if( findAttributeField( certInfoPtr->attributes,
							CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER, 
							CRYPT_ATTRIBUTE_NONE ) != NULL )
		{
		status = deleteCompleteAttribute( &certInfoPtr->attributes,
										  &certInfoPtr->attributeCursor, 
										  CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER, 
										  certInfoPtr->currentSelection.dnPtr );
		if( cryptStatusError( status ) )
			return( status );
		}

	return( CRYPT_OK );
	}
Ejemplo n.º 2
0
static int deleteCertAttribute( INOUT CERT_INFO *certInfoPtr,
								IN_ATTRIBUTE \
									const CRYPT_ATTRIBUTE_TYPE certInfoType )
	{
	ATTRIBUTE_PTR **attributeListHeadPtrPtr;
	ATTRIBUTE_PTR *attributePtr;
	const BOOLEAN isRevocationEntry = \
				isRevocationEntryComponent( certInfoType ) ? TRUE : FALSE;
	int status;

	assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );

	REQUIRES( isAttribute( certInfoType ) || \
			  isInternalAttribute( certInfoType ) );

	/* Try and find this attribute in the attribute list */
	attributePtr = findAttributeComponent( certInfoPtr, certInfoType );
	if( attributePtr == NULL )
		return( CRYPT_ERROR_NOTFOUND );

	/* If this is a non-present field with a default value in a present 
	   attribute (so that its value can be read but the field itself isn't 
	   really there) there isn't any terribly satisfactory return code to 
	   indicate this.  Returning CRYPT_OK is wrong because the caller can 
	   keep deleting the same field over and over, and returning 
	   CRYPT_ERROR_NOTFOUND is wrong because the caller may have added the 
	   attribute at an earlier date but it was never written because it had 
	   the default value so that to the caller it appears that the field 
	   they added has been lost.  The least unexpected action is probably to 
	   return CRYPT_OK */
	if( checkAttributeProperty( attributePtr, 
								ATTRIBUTE_PROPERTY_DEFAULTVALUE ) )
		return( CRYPT_OK );

	/* If this is a complete attribute (e.g. CRYPT_CERTINFO_SUBJECTINFOACCESS
	   rather than one of its fields like 
	   CRYPT_CERTINFO_SUBJECTINFO_CAREPOSITORY), delete the entire attribute */
	if( checkAttributeProperty( attributePtr,
								ATTRIBUTE_PROPERTY_COMPLETEATRIBUTE ) )
		{
		ATTRIBUTE_PTR *fieldAttributePtr;

		/* If the certificate has a fleur de lis make sure that it can't be 
		   scraped off */
		fieldAttributePtr = findAttribute( certInfoPtr->attributes,
										   certInfoType, TRUE );
		if( fieldAttributePtr != NULL && \
			checkAttributeProperty( fieldAttributePtr, 
									ATTRIBUTE_PROPERTY_LOCKED ) )
			return( CRYPT_ERROR_PERMISSION );

		/* This is an ID for an entire (constructed) attribute, delete the 
		   attribute */
		if( isRevocationEntry )
			{
			attributeListHeadPtrPtr = getEntryAttributeListHead( certInfoPtr );
			ENSURES( attributeListHeadPtrPtr != NULL );
			}
		else
			attributeListHeadPtrPtr = &certInfoPtr->attributes;
		return( deleteCompleteAttribute( attributeListHeadPtrPtr, 
										 &certInfoPtr->attributeCursor, certInfoType,
										 certInfoPtr->currentSelection.dnPtr ) );
		}

	/* If the certificate has a fleur de lis make sure that it can't be 
	   scraped off */
	if( checkAttributeProperty( attributePtr, ATTRIBUTE_PROPERTY_LOCKED ) )
		return( CRYPT_ERROR_PERMISSION );

	/* It's a single field, delete that */
	if( isRevocationEntry )
		{
		attributeListHeadPtrPtr = getEntryAttributeListHead( certInfoPtr );
		ENSURES( attributeListHeadPtrPtr != NULL );
		}
	else
		attributeListHeadPtrPtr = &certInfoPtr->attributes;
	status = deleteAttributeField( attributeListHeadPtrPtr,
								   &certInfoPtr->attributeCursor, attributePtr,
								   certInfoPtr->currentSelection.dnPtr );

	/* If we've deleted the attribute containing the currently selected DN, 
	   deselect it */
	if( status == OK_SPECIAL )
		{
		certInfoPtr->currentSelection.dnPtr = NULL;
		status = CRYPT_OK;
		}

	return( status );
	}
Ejemplo n.º 3
0
static int copyPkiUserAttributes( INOUT CERT_INFO *certInfoPtr,
								  INOUT ATTRIBUTE_PTR *pkiUserAttributes )
	{
	ATTRIBUTE_PTR *requestAttrPtr, *pkiUserAttrPtr;
	int value, status;

	assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
	assert( isWritePtr( pkiUserAttributes, sizeof( ATTRIBUTE_LIST ) ) );

	REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTREQUEST || \
			  certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT );

	/* If there are altNames present in both the PKI user data and the 
	   request, make sure that they match */
	requestAttrPtr = findAttribute( certInfoPtr->attributes,
									CRYPT_CERTINFO_SUBJECTALTNAME, FALSE );
	pkiUserAttrPtr = findAttribute( pkiUserAttributes,
									CRYPT_CERTINFO_SUBJECTALTNAME, FALSE );
	if( requestAttrPtr != NULL && pkiUserAttrPtr != NULL )
		{
		/* Both the certificate request and the PKI user have altNames,
		   make sure that they're identical */
		if( !compareAttribute( requestAttrPtr, pkiUserAttrPtr ) )
			{
			setErrorInfo( certInfoPtr, CRYPT_CERTINFO_SUBJECTALTNAME,
						  CRYPT_ERRTYPE_ISSUERCONSTRAINT );
			return( CRYPT_ERROR_INVALID );
			}

		/* The two altNames are identical, delete the one in the request in 
		   order to allow the one from the PKI user data to be copied across 
		   when we call copyAttributes() */
		status = deleteAttribute( &certInfoPtr->attributes,
								  &certInfoPtr->attributeCursor, 
								  requestAttrPtr,
								  certInfoPtr->currentSelection.dnPtr );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* 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 information indicates that 
	   they're intended to be a CA user.  The processing flow for this is:

			Read request data from an external source into certificate 
				request object, creating a state=high object;

			Add PKI user information to state=high request;

	   When augmenting the request with the PKI user information the 
	   incoming request will contain a keyUsage of digitalSignature while 
	   the PKI user information will contain a keyUsage of keyCertSign 
	   and/or crlSign.  We can't fix this up at the PnP processing level 
	   because the request object will be in the high state once it's
	   instantiated and no changes to the attributes can be made (the PKI 
	   user information is a special case that can be 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 keyUsage.  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 in the request's keyUsage, which makes it 
	   rather non-PnP and would also lead to slightly strange requests since
	   basicConstraints can't be specified in requests while the CA keyUsage
	   can */
	status = getAttributeFieldValue( certInfoPtr->attributes,
									 CRYPT_CERTINFO_KEYUSAGE, 
									 CRYPT_ATTRIBUTE_NONE, &value );
	if( cryptStatusOK( status ) && value == CRYPT_KEYUSAGE_DIGITALSIGNATURE )
		{
		status = getAttributeFieldValue( pkiUserAttributes, 
										 CRYPT_CERTINFO_KEYUSAGE,
										 CRYPT_ATTRIBUTE_NONE, &value );
		if( cryptStatusOK( status ) && ( value & KEYUSAGE_CA ) )
			{
			/* The certificate contains a digitalSignature keyUsage and the 
			   PKI user information contains a CA usage, delete the 
			   certificate's keyUsage to make way for the PKI user's CA 
			   keyUsage */
			status = deleteCompleteAttribute( &certInfoPtr->attributes,
											  &certInfoPtr->attributeCursor, 
											  CRYPT_CERTINFO_KEYUSAGE, 
											  certInfoPtr->currentSelection.dnPtr );
			if( cryptStatusError( status ) )
				return( status );
			}
		}

	/* Copy the attributes from the PKI user information into the 
	   certificate */
	status = copyAttributes( &certInfoPtr->attributes, pkiUserAttributes,
							 &certInfoPtr->errorLocus,
							 &certInfoPtr->errorType );
	if( cryptStatusError( status ) )
		return( status );

	/* Perform any special-case adjustments on attributes that may be 
	   required after they've been copied from the PKI user to the 
	   certificate request */
	return( adjustPkiUserAttributes( certInfoPtr ) );
	}