📄 dev_pk11.c
字号:
if( sBufPtr != sBuffer )
free( sBufPtr );
if( iAndSBufPtr != iAndSBuffer )
free( iAndSBufPtr );
if( certBufPtr != certBuffer )
free( certBufPtr );
return( cryptStatus );
}
/****************************************************************************
* *
* Device Init/Shutdown/Device Control Routines *
* *
****************************************************************************/
/* Prototypes for functions to get and free device capability information */
static void freeCapabilities( DEVICE_INFO *deviceInfo );
static int getCapabilities( DEVICE_INFO *deviceInfo );
/* Prototypes for device-specific functions */
static int getRandomFunction( DEVICE_INFO *deviceInfo, void *buffer,
const int length );
/* Close a previously-opened session with the device. We have to have this
before the init function since it may be called by it if the init process
fails */
static void shutdownFunction( DEVICE_INFO *deviceInfo )
{
/* Log out and close the session with the device */
if( deviceInfo->flags & DEVICE_LOGGEDIN )
C_Logout( deviceInfo->deviceHandle );
C_CloseSession( deviceInfo->deviceHandle );
deviceInfo->deviceHandle = CRYPT_ERROR;
deviceInfo->flags &= ~( DEVICE_ACTIVE | DEVICE_LOGGEDIN );
/* Free the device capability information */
freeCapabilities( deviceInfo );
}
/* Open a session with the device */
static int initFunction( DEVICE_INFO *deviceInfo, const char *name,
const int nameLength )
{
CK_SESSION_HANDLE hSession;
CK_SLOT_ID slotList[ MAX_PKCS11_SLOTS ];
CK_ULONG slotCount = MAX_PKCS11_SLOTS;
CK_TOKEN_INFO tokenInfo;
CK_RV status;
int tokenSlot = DEFAULT_SLOT, i, cryptStatus;
/* Get information on all available slots */
memset( slotList, 0, sizeof( slotList ) );
status = C_GetSlotList( TRUE, slotList, &slotCount );
if( status != CKR_OK )
return( mapError( deviceInfo, status, CRYPT_ERROR_OPEN ) );
if( !slotCount ) /* Can happen in some circumstances */
return( CRYPT_ERROR_OPEN );
/* Check whether a token name (used to select the slot) has been
specified */
for( i = 1; i < nameLength - 1; i++ )
if( name[ i ] == ':' && name[ i + 1 ] == ':' )
{
const void *tokenName = name + i + 2; /* Skip '::' */
const int tokenNameLength = nameLength - ( i + 2 );
if( tokenNameLength <= 0 )
return( CRYPT_ARGERROR_STR1 );
/* Check each slot for a token matching the given name */
for( tokenSlot = 0; tokenSlot < slotCount; tokenSlot++ )
{
status = C_GetTokenInfo( slotList[ tokenSlot ], &tokenInfo );
if( status == CKR_OK && \
!strnicmp( tokenName, tokenInfo.label, tokenNameLength ) )
break;
};
if( tokenSlot == slotCount )
return( CRYPT_ERROR_NOTFOUND );
}
deviceInfo->slotHandle = slotList[ tokenSlot ];
/* Get information on device-specific capabilities */
status = C_GetTokenInfo( deviceInfo->slotHandle, &tokenInfo );
if( status != CKR_OK )
{
shutdownFunction( deviceInfo );
return( mapError( deviceInfo, status, CRYPT_ERROR_OPEN ) );
}
if( tokenInfo.flags & CKF_RNG )
/* The device has an onboard RNG we can use */
deviceInfo->getRandomFunction = getRandomFunction;
if( tokenInfo.flags & CKF_WRITE_PROTECTED )
/* The device can't have data on it changed */
deviceInfo->flags |= DEVICE_READONLY;
if( tokenInfo.flags & CKF_LOGIN_REQUIRED )
/* The user needs to log in before using various device functions */
deviceInfo->flags |= DEVICE_NEEDSLOGIN;
if( ( deviceInfo->minPinSize = ( int ) tokenInfo.ulMinPinLen ) < 4 )
/* Some devices report silly PIN sizes */
deviceInfo->minPinSize = 4;
if( ( deviceInfo->maxPinSize = ( int ) tokenInfo.ulMaxPinLen ) < 4 )
/* Some devices report silly PIN sizes (setting this to ULONG_MAX or
4GB, which becomes -1 as an int, counts as silly). Since we can't
differentiate between 0xFFFFFFFF = bogus value and 0xFFFFFFFF =
ULONG_MAX we play it safe and set the limit to 8 bytes, which most
devices should be able to handle */
deviceInfo->maxPinSize = 8;
memcpy( deviceInfo->label, tokenInfo.label, 32 );
for( i = 32;
i && ( deviceInfo->label[ i - 1 ] == ' ' || \
!deviceInfo->label[ i - 1 ] ); i-- );
deviceInfo->label[ i ] = '\0';
/* Open a session with the device in the first slot. This gets a bit
awkward because we can't tell whether a R/W session is OK without
opening a session, but we can't open a session unless we know whether
a R/W session is OK, so first we try for a RW session and if that
fails we go for a read-only session */
status = C_OpenSession( deviceInfo->slotHandle,
CKF_RW_SESSION | CKF_SERIAL_SESSION, NULL_PTR,
NULL_PTR, &hSession );
if( status == CKR_TOKEN_WRITE_PROTECTED )
status = C_OpenSession( deviceInfo->slotHandle,
CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR,
&hSession );
if( status != CKR_OK )
{
cryptStatus = mapError( deviceInfo, status, CRYPT_ERROR_OPEN );
if( cryptStatus == CRYPT_ERROR_OPEN && \
!( tokenInfo.flags & CKF_USER_PIN_INITIALIZED ) )
/* We couldn't do much with the error code, it could be that the
token hasn't been initialised yet but unfortunately PKCS #11
doesn't define an error code for this condition. In addition
many tokens will allow a session to be opened and then fail
with a "PIN not set" error at a later point (which allows for
more accurate error reporting), however a small number won't
allow a session to be opened and return some odd-looking error
because there's nothing useful available. The best way to
report this in a meaningful manner to the caller is to check
whether the user PIN has been initialised, if it hasn't then
it's likely that the token as a whole hasn't been initialised
so we return a not initialised error */
cryptStatus = CRYPT_ERROR_NOTINITED;
return( cryptStatus );
}
deviceInfo->deviceHandle = hSession;
deviceInfo->flags |= DEVICE_ACTIVE;
/* Set up the capability information for this device */
cryptStatus = getCapabilities( deviceInfo );
if( cryptStatusError( cryptStatus ) )
{
shutdownFunction( deviceInfo );
return( ( cryptStatus == CRYPT_ERROR ) ? \
CRYPT_ERROR_OPEN : ( int ) cryptStatus );
}
return( CRYPT_OK );
}
/* Handle device control functions */
static int controlFunction( DEVICE_INFO *deviceInfo,
const CRYPT_ATTRIBUTE_TYPE type,
const void *data1, const int data1Length,
const void *data2, const int data2Length )
{
CK_RV status;
/* Handle user authorisation */
if( type == CRYPT_DEVINFO_AUTHENT_USER || \
type == CRYPT_DEVINFO_AUTHENT_SUPERVISOR )
{
/* If the user is already logged in, log them out before we try
logging in with a new authentication value */
if( deviceInfo->flags & DEVICE_LOGGEDIN )
{
C_Logout( deviceInfo->deviceHandle );
deviceInfo->flags &= ~DEVICE_LOGGEDIN;
}
/* Authenticate the user to the device */
status = C_Login( deviceInfo->deviceHandle,
( type == CRYPT_DEVINFO_AUTHENT_USER ) ? \
CKU_USER : CKU_SO, ( CK_CHAR_PTR ) data1,
( CK_ULONG ) data1Length );
if( status == CKR_OK || status == CKR_USER_ALREADY_LOGGED_IN )
deviceInfo->flags |= DEVICE_LOGGEDIN;
return( mapError( deviceInfo, status, CRYPT_ERROR_FAILED ) );
}
/* Handle authorisation value change */
if( type == CRYPT_DEVINFO_SET_AUTHENT_USER || \
type == CRYPT_DEVINFO_SET_AUTHENT_SUPERVISOR )
{
status = C_SetPIN( deviceInfo->deviceHandle, ( CK_CHAR_PTR ) data1,
( CK_ULONG ) data1Length, ( CK_CHAR_PTR ) data2,
( CK_ULONG ) data2Length );
return( mapError( deviceInfo, status, CRYPT_ERROR_FAILED ) );
}
/* Handle initialisation and zeroisation */
if( type == CRYPT_DEVINFO_INITIALISE || \
type == CRYPT_DEVINFO_ZEROISE )
{
CK_SESSION_HANDLE hSession;
CK_CHAR label[ 32 ];
/* If there's a session active with the device, log out and terminate
the session, since the token init will reset this */
if( deviceInfo->deviceHandle != CRYPT_ERROR )
{
C_Logout( deviceInfo->deviceHandle );
C_CloseSession( deviceInfo->deviceHandle );
}
deviceInfo->deviceHandle = CRYPT_ERROR;
/* Initialise/clear the device */
memset( label, ' ', 32 );
status = C_InitToken( deviceInfo->slotHandle,
( CK_CHAR_PTR ) data1,
( CK_ULONG ) data1Length, label );
if( status != CKR_OK )
return( mapError( deviceInfo, status, CRYPT_ERROR_FAILED ) );
/* Reopen the session with the device */
status = C_OpenSession( deviceInfo->slotHandle,
CKF_RW_SESSION | CKF_SERIAL_SESSION,
NULL_PTR, NULL_PTR, &hSession );
if( status != CKR_OK )
return( mapError( deviceInfo, status, CRYPT_ERROR_OPEN ) );
deviceInfo->deviceHandle = hSession;
/* If it's a straight zeroise, we're done */
if( type == CRYPT_DEVINFO_ZEROISE )
return( CRYPT_OK );
/* We're initialising it, log in as supervisor and set the initial
user PIN to the same as the SSO PIN. We do this because the init
user PIN functionality is a bit of an oddball function which has
to fill the gap between C_InitToken() (which sets the SSO PIN) and
C_SetPIN() (which can only set the SSO PIN for the SSO or the user
PIN for the user). Setting the user PIN by the SSO, which is
usually required to perform any useful (non-administrative)
function with the token, requires the special-case C_InitPIN().
Since the token will initially be used by the SSO we set it to the
same as the SSO PIN and rely on the user to change it before they
hand it over to the user. In most cases the user *is* the SSO, so
this ensures the device behaves as expected when the user isn't
even aware that there are SSO and user roles.
A useful side-effect of this is that it eliminates problems with
some devices which behave somewhat strangely if the SSO PIN is set
but the user PIN isn't */
status = C_Login( deviceInfo->deviceHandle, CKU_SO,
( CK_CHAR_PTR ) data1, ( CK_ULONG ) data1Length );
if( status == CKR_OK )
status = C_InitPIN( deviceInfo->deviceHandle,
( CK_CHAR_PTR ) data1,
( CK_ULONG ) data1Length );
if( status != CKR_OK )
{
C_Logout( deviceInfo->deviceHandle );
C_CloseSession( deviceInfo->deviceHandle );
deviceInfo->deviceHandle = CRYPT_ERROR;
return( mapError( deviceInfo, status, CRYPT_ERROR_FAILED ) );
}
/* We're logged in and ready to go */
deviceInfo->flags |= DEVICE_LOGGEDIN;
return( CRYPT_OK );
}
assert( NOTREACHED );
return( CRYPT_ERROR_NOTAVAIL ); /* Get rid of compiler warning */
}
/****************************************************************************
* *
* Misc.Device Interface Routines *
* *
****************************************************************************/
/* Get random data from the device */
static int getRandomFunction( DEVICE_INFO *deviceInfo, void *buffer,
const int length )
{
CK_RV status;
status = C_GenerateRandom( deviceInfo->deviceHandle, buffer, length );
return( mapError( deviceInfo, status, CRYPT_ERROR_FAILED ) );
}
/* Get the label for an object */
static int getObjectLabel( DEVICE_INFO *deviceInfo,
const CK_OBJECT_HANDLE hObject,
char *label, int *labelLength )
{
CK_ATTRIBUTE keyLabelTemplate = \
{ CKA_LABEL, NULL_PTR, 0 };
CK_RV status;
char labelBuffer[ CRYPT_MAX_TEXTSIZE ], *labelPtr = labelBuffer;
status = C_GetAttributeValue( deviceInfo->deviceHandle, hObject,
&keyLabelTemplate, 1 );
if( status == CKR_OK )
{
if( keyLabelTemplate.ulValueLen > CRYPT_MAX_TEXTSIZE && \
( labelPtr = malloc( ( size_t ) \
( keyLabelTemplate.ulValueLen ) ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
keyLabelTemplate.pValue = labelPtr;
status = C_GetAttributeValue( deviceInfo->deviceHandle, hObject,
&keyLabelTemplate, 1 );
}
if( status != CKR_OK )
{
*labelLength = 0;
if( label != NULL )
label[ 0 ] = '\0';
}
else
{
*labelLength = min( keyLabelTemplate.ulValueLen, CRYPT_MAX_TEXTSIZE );
if( label != NULL )
memcpy( label, labelPtr, *labelLength );
}
if( labelPtr != labelBuffer )
free( labelPtr );
return( mapError( deviceInfo, status, CRYPT_ERROR_FAILED ) );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -