📄 key_acl.c
字号:
* *
****************************************************************************/
/* It's a keyset action message, check the access conditions for the mechanism
objects */
int preDispatchCheckKeysetAccess( const int objectHandle,
const MESSAGE_TYPE message,
const void *messageDataPtr,
const int messageValue,
const void *dummy )
{
const MESSAGE_TYPE localMessage = message & MESSAGE_MASK;
const MESSAGE_KEYMGMT_INFO *mechanismInfo = \
( MESSAGE_KEYMGMT_INFO * ) messageDataPtr;
const KEYMGMT_ACL *keymgmtACL;
const int accessType = \
( localMessage == MESSAGE_KEY_GETKEY ) ? ACCESS_FLAG_R : \
( localMessage == MESSAGE_KEY_SETKEY ) ? ACCESS_FLAG_W : \
( localMessage == MESSAGE_KEY_DELETEKEY ) ? ACCESS_FLAG_D : \
( localMessage == MESSAGE_KEY_GETFIRSTCERT ) ? ACCESS_FLAG_F : \
( localMessage == MESSAGE_KEY_GETNEXTCERT ) ? ACCESS_FLAG_N : 0;
const OBJECT_INFO *objectTable = krnlData->objectTable;
OBJECT_SUBTYPE subType;
int paramObjectHandle, i;
/* Preconditions */
PRE( isValidObject( objectHandle ) );
PRE( localMessage == MESSAGE_KEY_GETKEY || \
localMessage == MESSAGE_KEY_SETKEY || \
localMessage == MESSAGE_KEY_DELETEKEY || \
localMessage == MESSAGE_KEY_GETFIRSTCERT || \
localMessage == MESSAGE_KEY_GETNEXTCERT );
PRE( isReadPtr( messageDataPtr, sizeof( MESSAGE_KEYMGMT_INFO ) ) );
PRE( messageValue > KEYMGMT_ITEM_NONE && \
messageValue < KEYMGMT_ITEM_LAST );
PRE( accessType != 0 );
/* Find the appropriate ACL for this mechanism */
for( i = 0; keyManagementACL[ i ].itemType != messageValue && \
keyManagementACL[ i ].itemType != KEYMGMT_ITEM_NONE && \
i < FAILSAFE_ARRAYSIZE( keyManagementACL, KEYMGMT_ACL );
i++ );
ENSURES( i < FAILSAFE_ARRAYSIZE( keyManagementACL, KEYMGMT_ACL ) );
ENSURES( keyManagementACL[ i ].itemType != KEYMGMT_ITEM_NONE );
keymgmtACL = &keyManagementACL[ i ];
/* Perform a combined check to ensure that the item type being accessed
is appropriate for this keyset type and the access type is valid */
subType = objectST( objectHandle );
switch( localMessage )
{
case MESSAGE_KEY_GETKEY:
if( !isValidSubtype( keymgmtACL->keysetR_subTypeA, subType ) && \
!isValidSubtype( keymgmtACL->keysetR_subTypeB, subType ) )
return( CRYPT_ARGERROR_OBJECT );
break;
case MESSAGE_KEY_SETKEY:
if( !isValidSubtype( keymgmtACL->keysetW_subTypeA, subType ) && \
!isValidSubtype( keymgmtACL->keysetW_subTypeB, subType ) )
return( CRYPT_ARGERROR_OBJECT );
break;
case MESSAGE_KEY_DELETEKEY:
if( !isValidSubtype( keymgmtACL->keysetD_subTypeA, subType ) && \
!isValidSubtype( keymgmtACL->keysetD_subTypeB, subType ) )
return( CRYPT_ARGERROR_OBJECT );
break;
case MESSAGE_KEY_GETFIRSTCERT:
case MESSAGE_KEY_GETNEXTCERT:
/* The two special-purpose accesses are differentiated by whether
there's state information provided. For a general query the
result set is determined by an initially-submitted query
which is followed by a sequence of fetches. For a getFirst/
getNext the results are determined by a cert identifier with
state held externally in the location pointed to by the
auxiliary info pointer */
if( mechanismInfo->auxInfo == NULL )
{
/* Keyset query. We report this as an arg error since we'll
have been passed a CRYPT_KEYID_NONE or empty keyID, this
is more sensible than an object error since there's
nothing wrong with the object, the problem is that
there's no keyID present */
if( !isValidSubtype( keymgmtACL->keysetQ_subTypeA, subType ) && \
!isValidSubtype( keymgmtACL->keysetQ_subTypeB, subType ) )
return( ( mechanismInfo->keyIDtype == CRYPT_KEYID_NONE ) ? \
CRYPT_ARGERROR_NUM1 : CRYPT_ARGERROR_STR1 );
}
else
{
/* getFirst/next. We can report an object error here since
this message is only sent internally */
if( !isValidSubtype( keymgmtACL->keysetFN_subTypeA, subType ) && \
!isValidSubtype( keymgmtACL->keysetFN_subTypeB, subType ) )
return( CRYPT_ARGERROR_OBJECT );
/* Inner precondition: The state information points to an
integer value containing a reference to the currently
fetched object */
PRE( isReadPtr( mechanismInfo->auxInfo, sizeof( int ) ) && \
mechanismInfo->auxInfoLength == sizeof( int ) );
}
break;
default:
retIntError();
}
/* Make sure that there's appropriate ID information present if
required */
if( keymgmtACL->idUseFlags & accessType )
{
const IDTYPE_ACL *idACL = NULL;
BOOLEAN keyIdOK = FALSE;
int index;
/* Make sure that the ID information is present and valid */
if( mechanismInfo->keyIDtype <= CRYPT_KEYID_NONE || \
mechanismInfo->keyIDtype >= CRYPT_KEYID_LAST )
return( CRYPT_ARGERROR_NUM1 );
if( !isInternalMessage( message ) && \
mechanismInfo->keyIDtype >= CRYPT_KEYID_LAST_EXTERNAL )
return( CRYPT_ARGERROR_NUM1 );
if( mechanismInfo->keyIDlength < MIN_NAME_LENGTH || \
mechanismInfo->keyIDlength >= MAX_ATTRIBUTE_SIZE || \
!isReadPtr( mechanismInfo->keyID, mechanismInfo->keyIDlength ) )
return( CRYPT_ARGERROR_STR1 );
/* Make sure that the key ID is of an appropriate type */
for( index = 0; \
keymgmtACL->allowedKeyIDs[ index ] != CRYPT_KEYID_NONE && \
index < FAILSAFE_ITERATIONS_SMALL; index++ )
{
if( keymgmtACL->allowedKeyIDs[ index ] == mechanismInfo->keyIDtype )
{
keyIdOK = TRUE;
break;
}
}
ENSURES( index < FAILSAFE_ITERATIONS_SMALL );
if( !keyIdOK )
{
/* If we try and retrieve an object using an inappropriate ID
type then this is a programming error, but not a fatal one,
so we just report it as an unable-to-find object error */
assert( DEBUG_WARN );
return( CRYPT_ERROR_NOTFOUND );
}
/* Finally, check that the keyID is valid for the keyset type. This
implements the third stage of the three-way check
keysetType :: itemType :: idType */
for( index = 0; idTypeACL[ index ].idType != KEYMGMT_ITEM_NONE && \
index < FAILSAFE_ARRAYSIZE( idTypeACL, IDTYPE_ACL );
index++ )
{
if( idTypeACL[ index ].idType == mechanismInfo->keyIDtype )
{
idACL = &idTypeACL[ index ];
break;
}
}
ENSURES( index < FAILSAFE_ARRAYSIZE( idTypeACL, IDTYPE_ACL ) );
if( idACL == NULL || \
!isValidSubtype( idACL->keysetSubTypeA, subType ) )
{
/* As before if we try and retrieve an object by an
inappropriate ID type then this is a nonfatal programming
error so we warn in the debug build but otherwise just report
it as an unable-to-find object error */
assert( DEBUG_WARN );
return( CRYPT_ERROR_NOTFOUND );
}
}
/* Make sure that there's a password present/not present if required.
We only check for incorrect parameters here if they were supplied by
the user, non-user-supplied parameters (which come from within
cryptlib) are checked by an assertion later on. For keyset objects
the password is optional on reads since it may be a label-only read
or an opportunistic read that tries to read the key without a
password initially and falls back to retrying with a password if this
fails, for device objects the password is never used since it was
supplied when the user logged on to the device.
Since the semantics of passwords for private keys are too complex to
express with a simple ACL entry, this check is hardcoded */
if( messageValue == KEYMGMT_ITEM_PRIVATEKEY || \
messageValue == KEYMGMT_ITEM_SECRETKEY )
{
if( objectTable[ objectHandle ].type == OBJECT_TYPE_KEYSET )
{
if( localMessage == MESSAGE_KEY_SETKEY && \
( mechanismInfo->auxInfo == NULL || \
mechanismInfo->auxInfoLength < MIN_NAME_LENGTH ||
mechanismInfo->auxInfoLength >= MAX_ATTRIBUTE_SIZE ) )
{
/* Private/secret key writes to a keyset must provide a
password */
return( CRYPT_ARGERROR_STR1 );
}
}
else
{
PRE( objectTable[ objectHandle ].type == OBJECT_TYPE_DEVICE );
if( ( mechanismInfo->flags != KEYMGMT_FLAG_LABEL_ONLY ) && \
( mechanismInfo->auxInfo != NULL || \
mechanismInfo->auxInfoLength != 0 ) )
{
/* Private/secret key access to a device doesn't use a
password, however the auxInfo parameter is also used to
contain the label for key label reads so we only check
it if it's a standard key read */
return( ( keymgmtACL->idUseFlags & accessType ) ? \
CRYPT_ARGERROR_STR2 : CRYPT_ARGERROR_STR1 );
}
}
}
/* Inner precondition: Only allowed flags are set, there's only one of
the usage preference flags set, and the object handle to get/set is
not present if not required (the presence and validity check when it
is required is performed further down) */
PRE( !( ~keymgmtACL->allowedFlags & mechanismInfo->flags ) );
PRE( mechanismInfo->flags >= KEYMGMT_FLAG_NONE && \
mechanismInfo->flags < KEYMGMT_FLAG_LAST );
PRE( ( mechanismInfo->flags & KEYMGMT_MASK_USAGEOPTIONS ) != \
KEYMGMT_MASK_USAGEOPTIONS );
PRE( localMessage == MESSAGE_KEY_SETKEY || \
mechanismInfo->cryptHandle == CRYPT_ERROR );
/* Inner precondition: There's ID information and a password/aux.data
present/not present as required. For a private key read the password
is optional so we don't check it, for a getFirst/getNext the aux.data
(a pointer to query state) is used when assembling a cert chain (state
held in the cert) and not used when performing a general query (state
held in the keyset) */
PRE( ( ( keymgmtACL->idUseFlags & accessType ) && \
mechanismInfo->keyIDtype != CRYPT_KEYID_NONE && \
isReadPtr( mechanismInfo->keyID, \
mechanismInfo->keyIDlength ) ) ||
( !( keymgmtACL->idUseFlags & accessType ) && \
mechanismInfo->keyIDtype == CRYPT_KEYID_NONE && \
mechanismInfo->keyID == NULL && \
mechanismInfo->keyIDlength == 0 ) );
PRE( ( ( messageValue == KEYMGMT_ITEM_PRIVATEKEY || \
messageValue == KEYMGMT_ITEM_SECRETKEY ) && \
localMessage == MESSAGE_KEY_GETKEY ) ||
localMessage == MESSAGE_KEY_GETFIRSTCERT ||
localMessage == MESSAGE_KEY_GETNEXTCERT ||
( ( keymgmtACL->pwUseFlags & accessType ) && \
isReadPtr( mechanismInfo->auxInfo, \
mechanismInfo->auxInfoLength ) ) ||
( !( keymgmtACL->pwUseFlags & accessType ) && \
mechanismInfo->auxInfo == NULL && \
mechanismInfo->auxInfoLength == 0 ) );
PRE( !( mechanismInfo->flags & KEYMGMT_FLAG_LABEL_ONLY ) || \
isReadPtr( mechanismInfo->auxInfo, \
mechanismInfo->auxInfoLength ) );
/* Perform message-type-specific checking of parameters */
switch( localMessage )
{
case MESSAGE_KEY_GETKEY:
break;
case MESSAGE_KEY_SETKEY:
/* Make sure that the object being set is valid and its type is
appropriate for this key management item (and via previous
checks, keyset) type. Note that this checks for inclusion in
the set of valid objects, in particular a public-key context
can have almost any type of certificate object attached but
will still be regarded as valid since the context meets the
check requirements. More specific object checks are performed
further on */
paramObjectHandle = mechanismInfo->cryptHandle;
if( !isValidObject( paramObjectHandle ) || \
!isSameOwningObject( objectHandle, paramObjectHandle ) )
return( CRYPT_ARGERROR_NUM1 );
subType = objectST( paramObjectHandle );
if( !isValidSubtype( keymgmtACL->objSubTypeA, subType ) && \
!isValidSubtype( keymgmtACL->objSubTypeB, subType ) )
{
/* If we're only allowed to add contexts, this could be a
cert object with an associated context, in which case
we look for an associated context and try again */
if( keymgmtACL->objSubTypeA != ST_CTX_PKC )
return( CRYPT_ARGERROR_NUM1 );
paramObjectHandle = findTargetType( paramObjectHandle,
OBJECT_TYPE_CONTEXT );
if( cryptStatusError( paramObjectHandle ) || \
objectST( paramObjectHandle ) != ST_CTX_PKC )
return( CRYPT_ARGERROR_NUM1 );
}
if( !isInHighState( paramObjectHandle ) && \
!( subType == ST_CERT_PKIUSER || subType == ST_CERT_REQ_REV ) )
{
/* PKI user info and revocation requests aren't signed. Like
private key password semantics, these are a bit too
complex to express in the ACL so they're hardcoded */
return( CRYPT_ARGERROR_NUM1 );
}
/* If we don't need to perform an specific-object check, we're
done */
subType = objectST( objectHandle );
if( !isValidSubtype( keymgmtACL->specificKeysetSubTypeA, subType ) && \
!isValidSubtype( keymgmtACL->specificKeysetSubTypeB, subType ) )
break;
/* We need a specific cert type for this keyset, make sure that
we've been passed this and not just a generic PKC-equivalent
object */
paramObjectHandle = findTargetType( mechanismInfo->cryptHandle,
OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( paramObjectHandle ) )
return( CRYPT_ARGERROR_NUM1 );
subType = objectST( paramObjectHandle );
if( !isValidSubtype( keymgmtACL->specificObjSubTypeA, subType ) && \
!isValidSubtype( keymgmtACL->specificObjSubTypeB, subType ) )
return( CRYPT_ARGERROR_NUM1 );
if( !isInHighState( paramObjectHandle ) )
return( CRYPT_ARGERROR_NUM1 );
break;
case MESSAGE_KEY_DELETEKEY:
break;
case MESSAGE_KEY_GETFIRSTCERT:
break;
case MESSAGE_KEY_GETNEXTCERT:
break;
default:
retIntError();
}
/* Postcondition: The access and parameters are valid and the object
being passed in is of the correct type if present. We don't
explicitly state this since it's just regurgitating the checks
already performed above */
return( CRYPT_OK );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -