📄 pgptokenlib.c
字号:
memcpy( output->id, templ[0].pValue, size );
}
else { /* was called to determine ID */
memcpy( output->id, pID, size );
output->id_size = size;
output->handle = input->handle;
output->obj_class = input->obj_class;
}
if( !isID )
free( pID );
return TRUE;
}
/* Get private key info, corresponding to the public object (public key or certificate) */
PGPBoolean static
sPubToPriv( PGPToken *tptr,
const pgpTokenKeyInfoPriv *pub,
pgpTokenKeyInfoPriv *priv )
{
CK_OBJECT_CLASS privClass = CKO_PRIVATE_KEY;
CK_BBOOL ktTrue = TRUE;
CK_KEY_TYPE keyType = CKK_RSA;
CK_ATTRIBUTE privTemplate[] =
{
{ CKA_ID, NULL, 0 }, /* must be the first */
{ CKA_CLASS, &privClass, sizeof(privClass) },
{ CKA_KEY_TYPE, &keyType, sizeof(keyType) },
{ CKA_TOKEN, &ktTrue, 1 }
};
return sObjToRelatedObj( tptr, pub,
privTemplate, sizeof(privTemplate), priv );
}
#if PGP_DEBUG
int sCacheIsSorted(const PGPTokenKeyInfo *cache, int n) {
int i;
int j;
unsigned smallest;
for( i=0; i<n; i++ ) {
smallest = *(unsigned*)cache[i].keyid;
for( j=i+1; j<n; j++ ) {
if( smallest > *(unsigned*)cache[j].keyid ) {
PGP_TOKEN_TRACE2("Sorting problem: [%d] > [%d]", i, j );
return 0;
}
}
}
return 1;
}
#endif
static PGPBoolean sKeyIDToKeyInfoFromCache(
PGPToken *tptr, const PGPByte *keyID,
pgpTokenKeyInfoPriv *cache, int n,
pgpTokenKeyInfoPriv *ki, PGPBoolean is_private )
{
int i;
const unsigned keyID_u = *(unsigned*)keyID;
int start_i=0;
int end_i;
PGPBoolean found=FALSE;
if( ki )
memset( ki, 0, sizeof(*ki) );
if( !n )
return FALSE;
pgpAssert( sCacheIsSorted((PGPTokenKeyInfo*)cache, n) );
end_i = n-1;
pgpAssert( keyID_u != 0 );
/* Perform binary search */
while( end_i - start_i > 1 ) {
const middle = start_i + (end_i - start_i) / 2;
const unsigned u = *(unsigned*)cache[middle].keyid;
if( keyID_u > u ) {
start_i = middle;
}
else if( keyID_u < u ) {
end_i = middle;
}
else {
break;
}
pgpAssert( end_i >= start_i );
}
pgpAssert( start_i <= end_i );
for (i = start_i ; i <= end_i; i ++) {
if( memcmp(keyID, cache[i].keyid, sizeof(cache[i].keyid))==0 ) {
found = TRUE;
break;
}
}
if( !found ) {
PGP_TOKEN_TRACE1( "sKeyIDToKeyInfoFromCache(keyID=%x): not found", *(unsigned*)keyID );
return FALSE;
}
if( ki ) {
if( is_private ) {
PGPBoolean ret;
ret = sPubToPriv( tptr, cache+i, ki );
if( !ret ) {
PGP_TOKEN_TRACE1(
"sKeyIDToKeyInfoFromCache: private key %x doesn't exist "
"(the guess based on public key was wrong)", *(unsigned*)(cache[i].keyid) );
/* zero keyid to be purged later */
memset( cache[i].keyid, 0, sizeof(cache[i].keyid) );
return FALSE;
}
}
else {
memcpy( ki, cache+i, sizeof(*ki) );
PGP_TOKEN_HANDLE_OK( ki->handle );
}
}
pgpAssert( ! ki || memcmp( ki->keyid, keyID, sizeof(ki->keyid) )==0 );
return TRUE;
}
/* purge cache from items with zero keyids */
static void sPurgeCache( PGPTokenKeyInfo * const ki, PGPSize *size ) {
PGPByte last_keyid[8];
int insize = (int)*size;
PGPTokenKeyInfo * ki2 = ki;
int i;
if( ki==NULL || size==0 )
return;
memset( last_keyid, 0, sizeof(last_keyid) );
/* check all but last */
for( i=0; i<insize-1; i++ ) {
if( *(unsigned*)ki2->keyid == 0 &&
memcmp(ki2->keyid, last_keyid, sizeof(last_keyid))==0 )
{
memcpy( ki2, ki2+1, sizeof(*ki2) );
insize--;
}
else
ki2++;
}
/* check the last */
if( *(unsigned*)ki2->keyid == 0 &&
memcmp(ki2->keyid, last_keyid, sizeof(last_keyid))==0 )
{
insize--;
}
pgpAssert( sCacheIsSorted( ki, insize ) );
pgpAssert( insize >= 0 );
*size = (PGPSize)insize;
}
/*
Return TRUE if the given token holds the given key.
If ki is not NULL, fill it with information about that key.
Two cases possible in the latter case:
we need handle to the CKO_PUBLIC_KEY (is_private=FALSE) or
we need handle to the CKO_SECRET_KEY key (is_private=TRUE)
*/
static PGPBoolean sKeyIDToPrivKeyInfo(PGPToken *tptr, const PGPByte *keyID,
pgpTokenKeyInfoPriv *ki, PGPBoolean is_private)
{
PGPUInt32 n;
pgpTokenKeyInfoPriv *block;
const unsigned keyID_u = *(unsigned*)keyID;
PGP_TOKEN_TRACE2( "sKeyIDToPrivKeyInfo(keyID=%x, is_private=%d)",
*(unsigned*)keyID, is_private );
/* Always look for details in priv key info, because it is the largest set */
block = (pgpTokenKeyInfoPriv *)sGetPrivKeyIDs(tptr, &n, FALSE);
#if PGP_DEBUG
if( !block || !n )
PGP_TOKEN_TRACE("No keys in cache");
#endif
if( sKeyIDToKeyInfoFromCache( tptr, keyID, block, n, ki, is_private ) ) {
return TRUE;
}
else { /* there is a possibility that cache was changed */
if( is_private )
sPurgeCache( tptr->privKeyIDs, &tptr->nPrivKeyIDs );
else
sPurgeCache( tptr->pubKeyIDs, &tptr->nPubKeyIDs );
return FALSE;
}
}
/*
Returns handle to the "PGP Public Key Data", which is a set of signed UserIDs,
without the PGP Public Key packet.
*/
static PGPBoolean sKeyIDToPubKeyInfo(PGPToken *tptr, const PGPByte *keyID,
pgpTokenKeyInfoPriv *ki )
{
PGPUInt32 n = 0;
pgpTokenKeyInfoPriv *block;
PGP_TOKEN_TRACE1( "sKeyIDToPubKeyInfo(keyID=%x)", *(unsigned*)keyID );
block = (pgpTokenKeyInfoPriv *)sGetPubKeyIDs(tptr, &n, FALSE);
return sKeyIDToKeyInfoFromCache( tptr, keyID, block, n, ki, FALSE );
}
/* Returns content of CKA_VALUE for the given handle */
static PGPByte *
sGetP11Value( PGPToken *tptr, CK_OBJECT_HANDLE handle, PGPSize *size ) {
PGPByte *value;
CK_RV rv;
CK_ATTRIBUTE dataTemplate = { CKA_VALUE, NULL, 0 };
int mapSize;
PGPByte *pubKeyPktOut=NULL;
int len_out=0;
PGP_TOKEN_TRACE("sGetP11Value");
rv = F->C_GetAttributeValue(tptr->session, handle, &dataTemplate, 1 );
if (rv != CKR_OK)
{
pgpDebugMsg( "C_GetAttributeValue failed" );
return NULL;
}
mapSize = dataTemplate.ulValueLen;
if( mapSize == 0 )
return NULL;
value = malloc( mapSize );
pgpAssert(value);
dataTemplate.pValue = value;
rv = F->C_GetAttributeValue(tptr->session, handle, &dataTemplate, 1);
if (rv != CKR_OK)
{
pgpDebugMsg( "C_GetAttributeValue failed" );
free(value);
value = NULL;
}
*size = mapSize;
return value;
}
/*
Create PGP Public Key Packet from the PKCS11 CKO_PUBLIC_KEY object.
Caller must free di.
*/
static PGPError
sGetP11PubKey( PGPToken *tptr, PGPByte *keyID, pgpTokenPubKeyStub *keyStub,
pgpTokenDataInfo **di )
{
CK_RV rv;
pgpTokenKeyInfoPriv ki;
*di = NULL;
/* Try to find CKO_PUBLIC_KEY */
sKeyIDToPrivKeyInfo( tptr, keyID, &ki, FALSE );
if( ki.handle == (CK_OBJECT_HANDLE)NULL ) {
PGP_TOKEN_TRACE("No PKCS11 public key objects found");
return kPGPError_NoErr;
}
/* Here we have the handle, referencing the CKO_PUBLIC_KEY object */
{
PGPByte *buf;
PGPByte *mod_buf;
PGPByte *exp_buf;
PGPUInt32 mod_size;
PGPUInt32 exp_size;
CK_ATTRIBUTE dataTmpl[] =
{
{ CKA_MODULUS, NULL, 0 },
{ CKA_PUBLIC_EXPONENT, NULL, 0 }
};
rv = F->C_GetAttributeValue(tptr->session, ki.handle, dataTmpl, 2);
mod_size = dataTmpl[0].ulValueLen;
exp_size = dataTmpl[1].ulValueLen;
buf = calloc( sizeof(pgpTokenDataInfo) + mod_size + exp_size, 1 );
if( IsNull( buf ) )
return kPGPError_OutOfMemory;
exp_buf = buf + sizeof(pgpTokenDataInfo); /* Exponent first */
mod_buf = exp_buf + exp_size; /* Modulus next */
dataTmpl[0].pValue = mod_buf;
dataTmpl[1].pValue = exp_buf;
rv = F->C_GetAttributeValue(tptr->session, ki.handle, dataTmpl, 2);
if (rv != CKR_OK) {
pgpDebugMsg( "C_GetAttributeValue failed" );
free( buf );
return kPGPError_SmartCardError;
}
{
pgpTokenDataInfo *p = (pgpTokenDataInfo*)buf;
p->alg = kPGPPublicKeyAlgorithm_RSA;
p->exp_size = exp_size;
p->mod_size = mod_size;
memcpy( &(p->pubKeyStub), keyStub, sizeof(p->pubKeyStub) );
}
*di = (pgpTokenDataInfo *)buf;
}
return kPGPError_NoErr;
}
/* Get missing key info from the given partially defined key object
buffer is temporary buffer, allocated/reallocated in this routine
*/
static PGPBoolean
sGetAllKeyInfo( PGPToken *tptr,
const pgpTokenKeyInfoPriv *input,
pgpTokenKeyInfoPriv *output,
void **buffer, int *buffer_size )
{
CK_RV rv;
const CK_OBJECT_HANDLE handle = input->handle;
const PGPBoolean isID = (PGPBoolean)input->id_size;
const PGPBoolean isKeyID = *(unsigned*)input->keyid;
CK_ATTRIBUTE modTemplate[] =
{
{ CKA_MODULUS, NULL, 0 },
{ CKA_LABEL, NULL, 0 },
{ CKA_ID, NULL, 0 } /* Must be last */
};
int modTemplateSize = sizeof(modTemplate)/sizeof(modTemplate[0]);
PGPByte *b = *buffer;
int b_size = *buffer_size;
int cur_len_mod, cur_len_id, cur_len_label, cur_len_sum;
PGPByte *label;
const PGPByte *id;
pgpTokenKeyInfoPriv *p_out_temp=NULL;
int p_out_temp_size=0;
if( handle == (CK_OBJECT_HANDLE)NULL ) {
memset( output, 0, sizeof(*output) );
pgpAssert( 0 );
return FALSE;
}
PGP_TOKEN_HANDLE_OK( handle );
memcpy( output, input, sizeof(*output) );
if( isID ) {
if( isKeyID ) {
PGP_TOKEN_TRACE("sGetAllKeyInfo: object already complete");
return TRUE; /* We know everything */
}
modTemplateSize --; /* We know ID */
}
rv = F->C_GetAttributeValue(tptr->session, handle, modTemplate, modTemplateSize);
if (rv != CKR_OK) {
pgpDebugMsg( "C_GetAttributeValue failed: no MODULUS" );
return FALSE;
}
cur_len_mod = modTemplate[0].ulValueLen;
cur_len_label = modTemplate[1].ulValueLen;
if( isID )
cur_len_id = 0;
else
cur_len_id = modTemplate[2].ulValueLen;
cur_len_sum = cur_len_mod + cur_len_id + cur_len_label;
pgpAssert( cur_len_mod > 8 );
if( cur_len_sum > b_size ) {
b = (b==NULL) ?
malloc( cur_len_sum ) :
realloc( b, b_size + cur_len_sum );
if( b == NULL ) {
*buffer = NULL;
*buffer_size = 0;
return FALSE; /* kPGPError_OutOfMemory */;
}
b_size += cur_len_sum;
*buffer = b;
*buffer_size = b_size;
}
modTemplate[0].pValue = b;
label = modTemplate[1].pValue = b + cur_len_mod;
if( isID )
id = input->id;
else
id = modTemplate[2].pValue = label + cur_len_label;
rv = F->C_GetAttributeValue(tptr->session, handle, modTemplate, modTemplateSize);
if (rv != CKR_OK) {
pgpDebugMsg( "C_GetAttributeValue failed" );
return FALSE;
}
/* Store CKA_ID for later */
if( !isID ) { /* ID was not given */
const label_longer = (cur_len_id >= sizeof(output->id));
memcpy( output->id, id,
label_longer ? sizeof(output->id) : cur_len_id );
if( !label_longer ) {
memset( output->id+cur_len_id, 0, sizeof(output->id)-cur_len_id );
output->id_size = cur_len_id;
}
#if PGP_DEBUG
else if( cur_len_id == sizeof(output->id) ) {
output->id_size = sizeof(output->id);
}
#endif
else {
pgpAssert(0);
/* We should work in this case, but I have never seen this. */
output->id_size = sizeof(output->id);
}
}
output->pgpData = TRUE;
/* Compare labels to see if this is a PGP token */
if( (cur_len_id > ID_LEN_MAX) /* never seen it */ ||
( ( cur_len_label != sizeof(labelPub)-1 ||
memcmp( label, labelPub, sizeof(labelPub)-1 )!=0 ) &&
( cur_len_label != sizeof(labelPubSub)-1 ||
memcmp( label, labelPubSub, sizeof(labelPubSub)-1 )!=0 ) ) )
{
/* not a PGP token -- take last KEYIDLEN bytes as keyid */
id = (PGPByte*)b+cur_len_mod - KEYIDLEN;
PGP_TOKEN_TRACE1( "Not a PGP object keyid=%x", *(unsigned*)id );
output->pgpData = FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -