⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pgptokenlib.c

📁 PGP8.0源码 请认真阅读您的文件包然后写出其具体功能
💻 C
📖 第 1 页 / 共 5 页
字号:
				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 + -