📄 pkcs11.c
字号:
PIN by the SSO, which is usually required to perform any useful (non-
administrative) function with the token, requires the special-case
C_InitPIN(). In addition we can't speculatively set the user PIN to
be the same as the SSO PIN (which would be useful because in most
cases the user *is* the SSO, thus ensuring that the device behaves as
expected when the user isn't even aware that there are SSO and user
roles) because devices that implement an FSM for initialisation will
move into an undesired state once the SSO -> user change is triggered.
The FSM for initialisation on devices that perform a multi-stage
bootstrap and require all of the various intialisation functions to
be used one after the other (e.g. Fortezza) is:
uninitialised/zeroised
v
C_InitToken (enter init or SSO PIN)
v
initialised
v
C_SetPIN (change init PIN -> SSO PIN)
v
SSO initialised
v
C_InitPIN (set user PIN)
v
user initialised
v
C_Logout
C_Login (move from SO -> user state)
The final logout/login is only needed with some tokens, in others
the move to user state is automatic once the user PIN is set by the
SO */
if( type == CRYPT_DEVINFO_SET_AUTHENT_SUPERVISOR )
{
/* Make sure that there's an SSO PIN present from a previous device
initialisation */
if( strlen( pkcs11Info->defaultSSOPIN ) <= 0 )
{
setErrorInfo( deviceInfo, CRYPT_DEVINFO_INITIALISE,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
/* Change the SSO PIN from the init PIN. Once we've done this we
clear the initial SSO PIN, since it's no longer valid in the new
state */
status = C_SetPIN( pkcs11Info->hSession, pkcs11Info->defaultSSOPIN,
strlen( pkcs11Info->defaultSSOPIN ),
( CK_CHAR_PTR ) data, ( CK_ULONG ) dataLength );
zeroise( pkcs11Info->defaultSSOPIN, CRYPT_MAX_TEXTSIZE );
return( mapError( pkcs11Info, status, CRYPT_ERROR_FAILED ) );
}
if( type == CRYPT_DEVINFO_SET_AUTHENT_USER )
{
status = C_InitPIN( pkcs11Info->hSession, ( CK_CHAR_PTR ) data,
( CK_ULONG ) dataLength );
return( mapError( pkcs11Info, 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( pkcs11Info->hSession != CRYPT_ERROR )
{
C_Logout( pkcs11Info->hSession );
C_CloseSession( pkcs11Info->hSession );
pkcs11Info->hSession = CRYPT_ERROR;
}
/* Initialise/clear the device, setting the initial SSO PIN */
memset( label, ' ', 32 );
status = C_InitToken( pkcs11Info->slotID,
( CK_CHAR_PTR ) data,
( CK_ULONG ) dataLength, label );
if( status != CKR_OK )
return( mapError( pkcs11Info, status, CRYPT_ERROR_FAILED ) );
/* Reopen the session with the device */
status = C_OpenSession( pkcs11Info->slotID,
CKF_RW_SESSION | CKF_SERIAL_SESSION,
NULL_PTR, NULL_PTR, &hSession );
if( status != CKR_OK )
return( mapError( pkcs11Info, status, CRYPT_ERROR_OPEN ) );
pkcs11Info->hSession = 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. In theory we could
also set the initial user PIN to the same as the SSO PIN at this
point because the user usually won't be aware of the presence of
an SSO role or the need to set a PIN for it, but this can run into
problems with tokens that only allow the user PIN to be modified
by the SSO after they've set it for the first time, so if the user
*is* aware of the existence of an SSO role then once they log in
as SSO they can no longer set the user PIN */
status = C_Login( pkcs11Info->hSession, CKU_SO,
( CK_CHAR_PTR ) data, ( CK_ULONG ) dataLength );
if( status != CKR_OK )
{
C_Logout( pkcs11Info->hSession );
C_CloseSession( pkcs11Info->hSession );
pkcs11Info->hSession = CRYPT_ERROR;
return( mapError( pkcs11Info, status, CRYPT_ERROR_FAILED ) );
}
/* Remember the default SSO PIN for use with a future C_SetPIN() */
memcpy( pkcs11Info->defaultSSOPIN, data, dataLength );
pkcs11Info->defaultSSOPIN[ dataLength ] = '\0';
/* We're logged in and ready to go */
deviceInfo->flags |= DEVICE_LOGGEDIN;
return( CRYPT_OK );
}
/* Handle high-reliability time */
if( type == CRYPT_IATTRIBUTE_TIME )
{
CK_TOKEN_INFO tokenInfo;
time_t *timePtr = ( time_t * ) data, theTime;
/* Get the token's time, returned as part of the token info
structure */
status = C_GetTokenInfo( pkcs11Info->slotID, &tokenInfo );
if( status != CKR_OK )
return( mapError( pkcs11Info, status, CRYPT_ERROR_SIGNALLED ) );
if( ( theTime = getTokenTime( &tokenInfo ) ) < MIN_TIME_VALUE )
return( CRYPT_ERROR_NOTAVAIL );
*timePtr = theTime;
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;
PKCS11_INFO *pkcs11Info = deviceInfo->devicePKCS11;
status = C_GenerateRandom( pkcs11Info->hSession, buffer, length );
return( mapError( pkcs11Info, status, CRYPT_ERROR_FAILED ) );
}
/* Get the label for an object. We can't use a dynBuf for this because it's
a PKCS #11 attribute rather than a cryptlib attribute */
static int getObjectLabel( PKCS11_INFO *pkcs11Info,
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( pkcs11Info->hSession, hObject,
&keyLabelTemplate, 1 );
if( status == CKR_OK )
{
if( keyLabelTemplate.ulValueLen > CRYPT_MAX_TEXTSIZE && \
( labelPtr = clAlloc( "getObjectLabel", \
( size_t ) ( keyLabelTemplate.ulValueLen ) ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
keyLabelTemplate.pValue = labelPtr;
status = C_GetAttributeValue( pkcs11Info->hSession, 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 )
clFree( "getObjectLabel", labelPtr );
return( mapError( pkcs11Info, status, CRYPT_ERROR_FAILED ) );
}
/* Instantiate a cert object from a handle */
static int instantiateCert( PKCS11_INFO *pkcs11Info,
const CK_OBJECT_HANDLE hCertificate,
CRYPT_CERTIFICATE *iCryptCert,
const BOOLEAN createContext )
{
CK_ATTRIBUTE dataTemplate = \
{ CKA_VALUE, NULL_PTR, 0 };
CK_RV status;
MESSAGE_CREATEOBJECT_INFO createInfo;
BYTE buffer[ MAX_BUFFER_SIZE ], *bufPtr = buffer;
int cryptStatus;
*iCryptCert = CRYPT_ERROR;
/* Fetch the cert data into local memory. We can't use a dynBuf for
this because it's a PKCS #11 attribute rather than a cryptlib
attribute */
status = C_GetAttributeValue( pkcs11Info->hSession, hCertificate,
&dataTemplate, 1 );
if( status == CKR_OK )
{
if( dataTemplate.ulValueLen > MAX_BUFFER_SIZE && \
( bufPtr = clAlloc( "instantiateCert", \
( size_t ) ( dataTemplate.ulValueLen ) ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
dataTemplate.pValue = bufPtr;
status = C_GetAttributeValue( pkcs11Info->hSession, hCertificate,
&dataTemplate, 1 );
}
if( status != CKR_OK )
{
if( bufPtr != buffer )
clFree( "instantiateCert", bufPtr );
return( mapError( pkcs11Info, status, CRYPT_ERROR_NOTFOUND ) );
}
/* Import the cert as a cryptlib object */
setMessageCreateObjectIndirectInfo( &createInfo, bufPtr,
dataTemplate.ulValueLen,
CRYPT_CERTTYPE_CERTIFICATE );
createInfo.arg1 = createContext ? CRYPT_CERTTYPE_CERTIFICATE : \
CERTFORMAT_DATAONLY;
cryptStatus = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
if( bufPtr != buffer )
clFree( "instantiateCert", bufPtr );
if( cryptStatusOK( cryptStatus ) )
*iCryptCert = createInfo.cryptHandle;
return( cryptStatus );
}
/* Get a cert chain from a device. This */
static int getCertChain( PKCS11_INFO *pkcs11Info,
const CRYPT_DEVICE iCertSource,
const CK_OBJECT_HANDLE hCertificate,
CRYPT_CERTIFICATE *iCryptCert,
const BOOLEAN createContext )
{
CK_ATTRIBUTE idTemplate = \
{ CKA_ID, NULL_PTR, 0 };
CK_RV status;
BYTE keyID[ MAX_BUFFER_SIZE ];
/* Find the ID for this cert */
status = C_GetAttributeValue( pkcs11Info->hSession, hCertificate,
&idTemplate, 1 );
if( status == CKR_OK && idTemplate.ulValueLen <= MAX_BUFFER_SIZE )
{
idTemplate.pValue = keyID;
status = C_GetAttributeValue( pkcs11Info->hSession, hCertificate,
&idTemplate, 1 );
}
if( status != CKR_OK || idTemplate.ulValueLen > MAX_BUFFER_SIZE )
/* We couldn't get the ID to build the chain or it's too large to be
usable, we can at least still return the individual cert */
return( instantiateCert( pkcs11Info, hCertificate, iCryptCert,
createContext ) );
/* Create the cert chain via an indirect import */
return( iCryptImportCertIndirect( iCryptCert, iCertSource,
CRYPT_IKEYID_KEYID, keyID, idTemplate.ulValueLen,
createContext ? KEYMGMT_FLAG_DATAONLY_CERT : 0 ) );
}
/* Find a certificate object based on various search criteria:
- Find cert matching a given label - certFromLabel()
- Find cert matching a given ID - certFromID()
- Find cert matching the ID of an object hObject - certFromObject()
- Find cert matching a supplied template - certFromTemplate()
- Find any X.509 cert - certFromLabel(), no label supplied.
These are general-purpose functions whose behaviour can be modified through
the following action codes */
typedef enum {
FINDCERT_NORMAL, /* Instantiate standard cert+context */
FINDCERT_DATAONLY, /* Instantiate data-only cert */
FINDCERT_P11OBJECT /* Return handle to PKCS #11 object */
} FINDCERT_ACTION;
static int findCertFromLabel( PKCS11_INFO *pkcs11Info,
const CRYPT_DEVICE iCertSource,
const char *label, const int labelLength,
CRYPT_CERTIFICATE *iCryptCert,
const FINDCERT_ACTION findAction )
{
static const CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
static const CK_CERTIFICATE_TYPE certType = CKC_X_509;
CK_ATTRIBUTE certTemplate[] = {
{ CKA_CLASS, ( CK_VOID_PTR ) &certClass, sizeof( CK_OBJECT_CLASS ) },
{ CKA_CE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -