📄 pgptokenlib.c
字号:
p_last = ki+j;
changed = TRUE;
}
}
/* swap */
if( changed ) {
memcpy( &last, p_last, sizeof(last) );
memmove( p_last/*dst*/, ki+i/*src*/, sizeof(*p_last) );
memcpy( ki+i/*dst*/, &last, sizeof(last) );
i--;
}
}
pgpAssert( sCacheIsSorted((PGPTokenKeyInfo*)ki, n) );
}
static void sInvalidateCache( PGPToken *tptr ) {
free( tptr->privKeyIDs );
free( tptr->pubKeyIDs );
tptr->privKeyIDs = tptr->pubKeyIDs = NULL;
tptr->nPrivKeyIDs = tptr->nPubKeyIDs = 0;
tptr->cachedTimeStamp = 0;
PGP_TOKEN_TRACE("Cache invalidated");
}
#if 0
/* PKCS11 callback -- for debug purposes */
static CK_RV CK_ENTRY sP11Callback(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_NOTIFICATION event,
CK_VOID_PTR pApplication /* same as passed to C_OpenSession. */ )
{
PGPToken *tptr = (PGPToken *)pApplication;
(void)hSession;
(void)event;
#if PGP_DEBUG
switch( event ) {
case CKN_SURRENDER:
PGP_TOKEN_TRACE("CKN_SURRENDER");
break;
case CKN_COMPLETE:
PGP_TOKEN_TRACE("CKN_COMPLETE");
break;
case CKN_DEVICE_REMOVED:
PGP_TOKEN_TRACE("CKN_DEVICE_REMOVED");
break;
default:
PGP_TOKEN_TRACE("?");
pgpAssert(0);
break;
}
#endif
return CKR_OK;
}
#endif
/* Copy public IDs, based on CKO_CERTIFICATE (i.e. those for which there is no
CKO_PUBLIC_KEY or PGP DATA object found), to the private ID cache.
These IDs will have obj_class==CKO_CERTIFICATE and later can be purged,
if no private key is available. This is needed for tokens which remove
CKO_PUBLIC_KEY object when appropriate certificate is saved on the token */
static PGPBoolean sAddPubIDsToPrivIDs( PGPToken *tptr ) {
int i;
int nCertBased=0;
PGPByte last_keyid[8];
pgpTokenKeyInfoPriv *p_priv_out = (pgpTokenKeyInfoPriv *)tptr->privKeyIDs;
int n_priv_out = tptr->nPrivKeyIDs;
#if 1 /* this is a simple solution (but not the best) to differentate certificate
without the private key from certificate with private key, when both have no
CKO_PUBLIC_KEY */
if( tptr->nPrivKeyIDs > 0 )
return TRUE; /* already found some CKO_PUBLIC_KEYs */
#endif
for( i=0; i<tptr->nPubKeyIDs; i++ )
if( ((pgpTokenKeyInfoPriv*)(tptr->pubKeyIDs+i))->obj_class == CKO_CERTIFICATE ) {
nCertBased++;
p_priv_out = (p_priv_out==NULL) ?
(pgpTokenKeyInfoPriv*)malloc( sizeof(pgpTokenKeyInfoPriv) ) :
(pgpTokenKeyInfoPriv*)realloc( p_priv_out,
(n_priv_out+1)*sizeof(pgpTokenKeyInfoPriv) );
memcpy( p_priv_out+n_priv_out, tptr->pubKeyIDs+i, sizeof(pgpTokenKeyInfoPriv) );
n_priv_out++;
}
if( nCertBased==0 )
return TRUE; /* nothing to copy */
sPrepareForCache( tptr, p_priv_out, n_priv_out );
/* Eliminate duplicates from sorted set.
We first zero duplicates and then call sPurgeCache */
tptr->privKeyIDs = (PGPTokenKeyInfo*)p_priv_out;
tptr->nPrivKeyIDs = n_priv_out;
memset( last_keyid, 0, sizeof(last_keyid) );
for( i=0; i<n_priv_out; i++, p_priv_out++ ) {
if( memcmp( last_keyid, p_priv_out->keyid, sizeof(last_keyid) )==0 ) {
/* keep last_keyid, remove CKO_CERTIFICATE first */
if( p_priv_out->obj_class == CKO_CERTIFICATE ) {
memset( p_priv_out->keyid, 0, sizeof(last_keyid) );
}
else {
memset( (p_priv_out-1)->keyid, 0, sizeof(last_keyid) );
}
#if PGP_DEBUG
nCertBased--;
#endif
}
else
memcpy( last_keyid, p_priv_out->keyid, sizeof(last_keyid) );
}
pgpAssert( nCertBased>=0 /* should not have duplicates before */ );
sPurgeCache( tptr->privKeyIDs, &tptr->nPrivKeyIDs );
pgpAssert( sCacheIsSorted(tptr->privKeyIDs, tptr->nPrivKeyIDs) );
PGP_TOKEN_TRACE1( "sCopyPubIDsToPrivIDs: %d cert-based pub. keyids copied into priv. keyid set", nCertBased );
PGP_TOKEN_TRACE1( "sCopyPubIDsToPrivIDs: 1st: %x",
tptr->nPrivKeyIDs ? *(unsigned*)(tptr->privKeyIDs[0].keyid) : 0 );
return TRUE;
}
/* Find all private keys on the card by reading CKO_PUBLIC_KEY objects.
This will work for PGP-generated and browser-generated cards.
Caller must free returned array n_out PGPTokenKeyInfos.
There are more or equal "private keys" then "public"
*/
static PGPTokenKeyInfo*
sGetPrivKeyIDs(PGPToken *tptr, PGPSize *n_out, PGPBoolean is_dup )
{
int howmany=0;
CK_OBJECT_HANDLE *handles=NULL;
const CK_OBJECT_CLASS key = CKO_PUBLIC_KEY;
/* We use public key, because it doesn't require PIN */
const CK_KEY_TYPE keyType = CKK_RSA;
CK_ATTRIBUTE templRsa[] =
{
{ CKA_CLASS, (CK_OBJECT_CLASS *)&key, sizeof(key) },
{ CKA_KEY_TYPE, (CK_KEY_TYPE *)&keyType , sizeof(keyType ) },
};
void *buffer=NULL;
int buffer_size=0;
pgpTokenKeyInfoPriv *p_out_temp=NULL;
int p_out_temp_size=0;
int i;
*n_out = 0;
if (!tptr->have_session)
{
pgpDebugMsg( "sGetPrivKeyIDs called with no smartcard session" );
return NULL;
}
sCheckCache( tptr );
if( tptr->privKeyIDs ) {
PGPTokenKeyInfo *out =
is_dup ? sDupKeyIDs( tptr->privKeyIDs,
tptr->nPrivKeyIDs ) : tptr->privKeyIDs;
pgpAssert( sCacheIsSorted(tptr->privKeyIDs, tptr->nPrivKeyIDs) );
if( out )
*n_out = tptr->nPrivKeyIDs;
return out;
}
/* IDs were not cached. Read data from the card. */
handles = sFindP11Objs( tptr, templRsa, sizeof(templRsa), &howmany, NULL, 0 );
for( i=0; i<howmany; i++ ) {
pgpTokenKeyInfoPriv input;
memset( &input, 0, sizeof(input) );
input.handle = handles[i];
input.obj_class = CKO_PUBLIC_KEY;
p_out_temp = (p_out_temp==NULL) ?
(pgpTokenKeyInfoPriv*)malloc( sizeof(pgpTokenKeyInfoPriv) ) :
(pgpTokenKeyInfoPriv*)realloc( p_out_temp,
(p_out_temp_size+1)*sizeof(pgpTokenKeyInfoPriv) );
if( p_out_temp == NULL )
break;
if( !sGetAllKeyInfo(
tptr, &input, p_out_temp+p_out_temp_size,
&buffer, &buffer_size )
)
{
pgpAssert(0);
break;
}
p_out_temp_size ++;
}
free( handles );
free( buffer );
if( i != howmany ) {
free( p_out_temp );
return NULL;
}
/* Put private IDs into the cache */
sPrepareForCache(tptr, p_out_temp, p_out_temp_size);
tptr->nPrivKeyIDs = p_out_temp_size;
tptr->privKeyIDs = (PGPTokenKeyInfo*)p_out_temp;
sAddPubIDsToPrivIDs( tptr );
{
PGPTokenKeyInfo *out = is_dup ?
sDupKeyIDs( tptr->privKeyIDs, tptr->nPrivKeyIDs ) : tptr->privKeyIDs;
if( out ) {
*n_out = tptr->nPrivKeyIDs;
PGP_TOKEN_TRACE1("sGetPrivKeyIDs: cache created for %d keys", tptr->nPrivKeyIDs );
}
return out;
}
}
static PGPTokenKeyInfo*
sGetPubKeyIDs(PGPToken *tptr, PGPSize *n, PGPBoolean is_dup)
{
PGPTokenKeyInfo *out;
PGPSize n_certs=0;
if (!tptr->have_session)
{
pgpDebugMsg( "sGetPubKeyIDs called with no smartcard session" );
return NULL;
}
pgpAssert( n );
sCheckCache(tptr);
if( tptr->pubKeyIDs ) {
pgpAssert( tptr->nPubKeyIDs );
out = is_dup ?
sDupKeyIDs( tptr->pubKeyIDs, tptr->nPubKeyIDs ) :
tptr->pubKeyIDs;
if( out ) {
*n = tptr->nPubKeyIDs;
pgpAssert( sCacheIsSorted(tptr->pubKeyIDs, tptr->nPubKeyIDs) );
}
return out;
}
/* IDs were not cached. Read data from the card. */
out = sGetPubKeyIDsFromPgpData( tptr, n );
sPrepareForCache( tptr, (pgpTokenKeyInfoPriv*)out, *n );
out = sGetPubKeyIDsFromCerts( tptr, out, *n, &n_certs );
*n += n_certs;
/* Put public IDs into cache */
sPrepareForCache( tptr, (pgpTokenKeyInfoPriv*)out, *n );
if( out ) {
tptr->nPubKeyIDs = *n;
tptr->pubKeyIDs = out;
if( out == NULL )
*n = 0;
else {
if( is_dup ) {
if( (out = sDupKeyIDs( out, *n )) == NULL )
*n = 0;
}
pgpAssert( sCacheIsSorted(out, *n) );
PGP_TOKEN_TRACE1("sGetPubKeyIDs: cache created for %d keys", *n);
}
}
return out;
}
/* Puts key container for the key pair,
corresponding to keyID, or returns key container.
uuid can be NULL, or not NULL.
if uuid is not NULL,
uuid on the input contains UUID of the containter that
the caller wants to create.
If valid containers exist for the keyID, they will
be destroyed.
uuidOut can be NULL or not NULL.
if uuidOut is not NULL,
on the output uuidOut contains UUID of existing
key container (possibly just created).
This is designed to import X509 certificates into Internet Explorer.
This implementation uses format, understandable by iKey.
For other tokens we still use the same (straightforward) format to store
key container information, otherwise not visible in the PKCS11
object model. So, you should realize that technically, we create a key
container only for iKey. For other cards, we create something
like reflection of key container.
This is the only CryptoAPI-related piece in this file. One day vendors
may provide other means for reading key container for existing keypair
in the PKCS11 object model in the way, similiar to the iKey.
*/
static PGPError
sPutGetKeyContainer( PGPToken *tptr,
const PGPByte *keyID,
PGPBoolean destroyExisting,
const PGPByte *uuid, PGPSize uuid_size,
PGPByte **uuidOut, PGPSize *uuidOutSize )
{
#ifdef PGP_WIN32
/* Used for IExplorer only */
PGPError ret = kPGPError_SmartCardError;
CK_RV rv;
CK_OBJECT_HANDLE *handles = NULL;
CK_OBJECT_HANDLE handle;
CK_BBOOL True = TRUE;
CK_BBOOL False = FALSE;
CK_OBJECT_CLASS data = CKO_DATA;
PGPByte newID_padded[ID_PADDED_LEN] = { '\0' };
PGPBoolean dontCreate = FALSE;
unsigned howmany;
CK_ATTRIBUTE srchTemplate[] =
{
{ CKA_CLASS, &data, sizeof(data) },
{ CKA_TOKEN, &True, 1 },
{ CKA_PRIVATE, &False, 1 },
{ CKA_APPLICATION, "v2.0", 4 },
/* Search part ends here */
{ CKA_LABEL, (void*)uuid, uuid_size },
{ CKA_VALUE, newID_padded, sizeof(newID_padded) }
};
const srchTemplateSize = sizeof(srchTemplate)/sizeof(srchTemplate[0]);
/* This is true for Windows: */
pgpAssert( uuid_size==0 || uuid_size >= 0xE );
if( uuidOut != NULL )
*uuidOut = NULL;
if( uuidOutSize != NULL )
*uuidOutSize = 0;
PGP_TOKEN_TRACE2( "sPutGetKeyContainer(%x,%s)", *(unsigned*)keyID, uuid ? uuid : "NULL" );
/* Do some consistency checks first... */
if( ! sKeyIDToPubKeyInfo( tptr, keyID, NULL ) ) {
PGP_TOKEN_TRACE( "sPutGetKeyContainer specifies unknown keyID. Exiting..." );
return kPGPError_SmartCardError;
/* No keyID on this card -- will not create key container */
}
if (!(tptr->logged_in))
{
pgpDebugMsg( "sPutGetKeyContainer being called when not logged in" );
return kPGPError_SmartCardKeyNotFound;
}
memcpy( newID_padded, keyID, KEYIDLEN );
/* Search for all data objects. We do not put ID here, because
we want to support all containers: with KEYIDLEN,
or ID_PADDED_LEN ID length. One vendor is sensitive
for exact match for the attribute length specified in the
template to the one actually on the token.
*/
handles = sFindP11Objs( tptr, srchTemplate,
sizeof(srchTemplate)-2*sizeof(srchTemplate[0]), &howmany, NULL, 0 );
if( handles != NULL )
{
unsigned i=0;
PGPByte id[ID_PADDED_LEN] = { '\0' }; /* No more then ID_PADDED_LEN, OK to fail if more */
PGPByte *curr_uuid = NULL;
PGPSize curr_uuid_len = 0;
CK_ATTRIBUTE t[] =
{
{ CKA_LABEL, NULL, 0 }, /* UUID */
{ CKA_VALUE, NULL, 0 } /* ID, bounded by ID_PADDED_LEN */
};
/* Compare KeyID */
for( i=0; i<howmany; i++ ) {
t[0].pValue = NULL;
t[1].pValue = NULL;
rv = F->C_GetAttributeValue(tptr->session, handles[i], t, 2);
if (rv != CKR_OK) {
pgpDebugMsg( "C_GetAttributeValue failed" );
free(handles);
return kPGPError_SmartCardError;
}
/* Set CKA_LABEL */
pgpAssert( t[0].type == CKA_LABEL );
if( curr_uuid_len < t[0].ulValueLen ) {
curr_uuid_len = t[0].ulValueLen;
curr_uuid = curr_uuid ? realloc( curr_uuid, curr_uuid_len ) :
malloc( curr_uuid_len );
if( curr_uuid == NULL ) {
free(handles);
return kPGPError_OutOfMemory;
}
}
t[0].pValue = curr_uuid;
*curr_uuid = '\0'; /* Make sure -- we reuse buffer */
/* Set CKA_VALUE */
pgpAssert( t[1].type == CKA_VALUE );
if( t[1].ulValueLen > ID_PADDED_LEN )
continue;
t[1].pValue = id; /* ID is stored in CKA_VALUE */
rv = F->C_GetAttributeValue(tptr->session, handles[i], t, 2);
if (rv != CKR_OK) {
pgpDebugMsg( "C_GetAttributeValue failed" );
continue; /* Allowed fail */
}
if( memcmp( keyID, id, KEYIDLEN ) == 0 ) { /* KeyID match */
/* Here, we beleive we have a key container. Either return it,
or destroy */
if( destroyExisting ) {
if(howmany == 1 && uuid && memcmp( curr_uuid, uuid, uuid_size )==0)
{
/* We have exactly what needed. Do not delete/create */
break;
}
PGP_TOKEN_TRACE1( "sPutGetKeyContainer: Destroy container %s", curr_uuid );
rv = F->C_DestroyObject( tptr->session, handles[i] );
if (rv != CKR_OK)
pgpDebugMsg( "C_DestroyObject failed, but we are continuing" );
continue;
/* Go through all valid containers,
in case there is a corruption */
}
else
ret = kPGPError_NoErr;
break;
}
}
free( handles );
if( curr_uuid[0] && i<howmany && IsntPGPError(ret) ) {
pgpAssert( !destroyExisting );
/* Otherwise, we should already destroy all of them */
if( uuidOut )
*uuidOut = curr_uuid; /* pass allocated buffer to the caller */
if( uuidOutSize )
*uuidOutSize = curr_uuid_len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -