📄 pgptokenlib.c
字号:
/*____________________________________________________________________________
Copyright (C) 2002 PGP Corporation
All rights reserved.
$Id: pgpTokenLib.c,v 1.92 2002/08/06 20:11:04 dallen Exp $
____________________________________________________________________________*/
#include "pgpSDKBuildFlags.h"
#define PGP_TRACE_P11 1 /* Extensive logging on the debug console */
#ifndef CRYPTOKIDLL
#define CRYPTOKIDLL "slbck.dll"
#endif
#include "windows.h"
#pragma pack(push, cryptoki, 1)
#include "pkcs11.h"
#pragma pack(pop, cryptoki)
#include "pgpConfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pgpTokenLib.h"
#include "pgpMem.h"
#include "pgpErrors.h"
#include "pgpUsuals.h"
#define KEYIDLEN 8
#define ID_PADDED_LEN 20
/* For IE with old "Datakey RSA CSP" 20 is requirement.
20 is a size Netscape/IE uses (SHA-1) for keys
generated within the browser.
However, 8 works with Netscape 4.7 and 6.0 and IE.
*/
#define ID_LEN_MAX 48 /* This is a maximum I saw */
#if ID_PADDED_LEN < KEYIDLEN || ID_PADDED_LEN > ID_LEN_MAX || KEYIDLEN > ID_LEN_MAX
#error
#endif
#define CKR_PIN_LOCKED_2 0xA4
#undef pgpAssert
#ifdef PGP_WIN32
#include <assert.h>
#define pgpAssert assert
#else
#define pgpAssert(x)
#endif
#define sCheckCache(tptr)
static CK_FUNCTION_LIST_PTR F;
static PGPToken token[MAXTOKENS];
static PGPBoolean is_CRYPTOKI_initialized = FALSE;
static int s_how_many_tokens = -1; /* don't know */
static PGPBoolean enable_checking = TRUE;
static PGPUInt32 *now_slots = NULL;
static PGPUInt32 now_slots_allocated = 0;
static PGPByte CryptoKiDll[255] = CRYPTOKIDLL;
static pgpTokenCertToKeyID sCertToKeyID = NULL;
static void *sCertToKeyID_param = NULL;
/*** FORWARD DECLARATIONS ***/
static void PKCS11ConstructTokenFields(PGPToken *tptr);
static PGPError PKCS11ConstructAllTokenFields(void);
static PGPError PKCS11PutPublicData(PGPToken *tptr, PGPByte *keyID,
PGPByte *pubKeyBlock, PGPSize size,
pgpTokenDataInfo *di );
static PGPError PKCS11PutPrivate(PGPToken *tptr, PGPBoolean is_master,
TCL_PRIVATE_KEY_DATA_LIST);
static PGPError PKCS11Delete(PGPToken *tptr, const PGPByte *keyID, PGPBoolean is_last );
static PGPByte * PKCS11GetPublicData(PGPToken *tptr, PGPByte *keyID,
PGPSize *size, pgpTokenDataInfo **di);
static PGPTokenCertInfo * PKCS11GetCerts(PGPToken *tptr, PGPTokenKeyInfo *keyID,
PGPInt32 *n);
static PGPByte * PKCS11GetCert(PGPToken *tptr, PGPTokenCertInfo *certInfo,
PGPSize *size);
static PGPTokenKeyInfo*sGetPubKeyIDs(PGPToken *tptr, PGPSize *n, PGPBoolean is_dup);
static PGPTokenKeyInfo*PKCS11GetPubKeyIDs(PGPToken *tptr, PGPSize *n);
static PGPTokenKeyInfo*sGetPrivKeyIDs(PGPToken *tptr, PGPSize *n_out, PGPBoolean is_dup );
static PGPTokenKeyInfo*PKCS11GetPrivKeyIDs(PGPToken *tptr, PGPSize *n);
static PGPError PKCS11Logout(PGPToken *tptr);
static PGPError PKCS11Login(PGPToken *tptr, char const *input,
PGPSize length);
static PGPError PKCS11Sign(PGPToken *tptr, CK_BYTE *keyID, CK_BYTE *in,
PGPSize isize, CK_BYTE *out,
PGPSize osize);
static PGPError PKCS11Decrypt(PGPToken *tptr, CK_BYTE *keyID,
CK_BYTE *in, PGPSize isize,
CK_BYTE *out, PGPSize osize);
static PGPError PKCS11Destroy(PGPToken *tptr);
static PGPError PKCS11Init(PGPToken *tptr, PGPUInt32 whichslot,
PGPBoolean haveslot, PGPInt32 tokenNum);
static PGPError PKCS11Keygen(PGPToken *tptr, PGPByte *ID,
PGPSize modulusSize, PGPBoolean genMaster, PGPByte *modulus,
PGPByte *pubExp, PGPSize *pubExpSize );
static PGPError PKCS11EditKeyList(PGPToken *tptr, PGPByte *origID,
PGPByte *newID);
static PGPError PKCS11SetPIN(PGPToken *tptr, char *oldPIN,
PGPSize oldPINsize, char *newPIN,
PGPSize newPINsize);
static PGPError PKCS11Wipe(PGPToken *tptr);
static PGPError PKCS11Format(PGPToken *tptr,
PGPByte const *so_pin, PGPSize so_pin_len,
PGPByte const *new_user_pin, PGPSize new_user_pin_len );
static PGPError PKCS11GetInfo( PGPToken *tptr,
PGPTokenInfo *tokenInfo );
static PGPError PKCS11ImportX509(PGPToken *tptr, const PGPByte *keyID,
const PGPByte *userID, PGPSize userID_len,
const PGPByte *x509, PGPSize x509_len,
const PGPByte *subjDER, PGPSize subjDER_len,
const PGPByte *issuerDER, PGPSize issuerDER_len,
const PGPByte *sn, PGPSize sn_len );
static PGPError PKCS11PutKeyContainer( PGPToken *tptr,
const PGPByte *keyID,
const PGPByte *uuid, PGPSize uuidSize );
static PGPError PKCS11GetKeyContainer( PGPToken *tptr,
const PGPByte *keyID,
PGPByte **uuidOut, PGPSize *uuidOutSize );
#if defined(PGP_DEBUG) && PGP_DEBUG != 0 && defined(PGP_TRACE_P11)
#include <stdarg.h>
void spgpTokenLibTrace(const char *file, int line, const char *fmt, ...) {
va_list marker;
char s[1024];
char s2[1024];
const char *p = strrchr( file, '\\' );
if( p )
file = p+1;
va_start( marker, fmt );
vsprintf( s, fmt, marker );
va_end( marker );
sprintf( s2, "%s(%d): %s\n", file, line, s );
#ifdef PGP_WIN32
OutputDebugString( s2 );
#else
printf( s2 ); /* TODO: logging for other platforms */
#endif
}
#define PGP_TOKEN_TRACE( s ) spgpTokenLibTrace( __FILE__, __LINE__, s )
#define PGP_TOKEN_TRACE1( s, p1 ) spgpTokenLibTrace( __FILE__, __LINE__, s, p1 )
#define PGP_TOKEN_TRACE2( s, p1,p2 ) spgpTokenLibTrace( __FILE__, __LINE__, s, p1,p2 )
#define PGP_TOKEN_TRACE3( s, p1,p2,p3 ) spgpTokenLibTrace( __FILE__, __LINE__, s, p1,p2,p3 )
#else
#define PGP_TOKEN_TRACE( s )
#define PGP_TOKEN_TRACE1( s, p1 )
#define PGP_TOKEN_TRACE2( s, p1,p2 )
#define PGP_TOKEN_TRACE3( s, p1,p2,p3 )
#endif
/* Check for the uninitialized values */
#define PGP_TOKEN_HANDLE_OK( handle ) \
pgpAssert( (handle) != 0xcdcdcdcd && (handle) != 0xcccccccc && (handle) != (-1) );
#pragma pack(push, _pgpTokenKeyInfoPriv, 1)
typedef struct _pgpTokenKeyInfoPriv {
PGPByte keyid[KEYIDLEN];
PGPBoolean pgpData;
PGPUInt8 alg; /* kPGPPublicKeyAlgorithm_RSA */
PGPInt16 id_size; /* CKA_ID, connecting related objects */
CK_OBJECT_CLASS obj_class; /* type of 'handle' */
CK_OBJECT_HANDLE handle;/* corresponding PKCS11 object
(PGP data object or PKCS11 public key) */
PGPByte id[ID_LEN_MAX];
} pgpTokenKeyInfoPriv;
#pragma pack(pop, _pgpTokenKeyInfoPriv)
typedef struct _pgpTokenCertInfoPriv {
PGPByte keyid[KEYIDLEN];
CK_OBJECT_HANDLE handle; /* X509 cert object */
} pgpTokenCertInfoPriv;
/****** INTERNAL FUNCTIONS ********/
/* Labels are likely to be visible to the user in viewers/browsers.
It is safe to change them only here */
const static CK_CHAR application[] = "PGP";
static const CK_CHAR labelPrefix[] = "PGP Key Data 0x";
static PGPByte certLabelPrefix[] = "PGP Cert. ";
/* + user identity + */
static PGPByte certLabelSuffix[] = " 0x";
/* + keyID */
static CK_CHAR labelPub[] = "PGP Public Key";
static CK_CHAR labelPubSub[] = "PGP Public Subkey";
static CK_CHAR labelPriv[] = "PGP Private Key";
static CK_CHAR labelPrivSub[] = "PGP Private Subkey";
typedef PGPByte pgpPubKeyDataLabel[sizeof(labelPrefix)+2*KEYIDLEN];
/* Given KeyID, outputs string representation of it into 'out'
Returns the number of bytes written
*/
static unsigned
sKeyIDToString( const PGPByte *keyID, PGPByte out[2*KEYIDLEN], PGPBoolean compat )
{
int i;
unsigned off=0;
if( out == NULL )
return KEYIDLEN * ( compat ? 1 : 2 );
for( i = compat ? KEYIDLEN/2 : 0; i<KEYIDLEN; ++i )
{
PGPByte c = (keyID[i] >> 4) & 0xf;
out[off++] = (c > 9) ? ('A'+c-10) : ('0'+c);
c = keyID[i] & 0xf;
out[off++] = (c > 9) ? ('A'+c-10) : ('0'+c);
}
return off;
}
/* Create label for public key data blob */
static void sKeyIDToPublicLabel( const PGPByte *keyID, CK_ULONG *size, pgpPubKeyDataLabel label )
{
CK_ULONG off;
memcpy( label, labelPrefix, sizeof(labelPrefix)-1 );
off = sizeof(labelPrefix) - 1;
off += sKeyIDToString( keyID, label + off, FALSE );
*size = off;
}
/* Create label for PKCS11 cert. Caller must free it.
size doesn't include '\0' character (but string has it) */
static PGPByte *
sKeyIDToP11CertLabel( const PGPByte *keyID,
const PGPByte *userID, PGPSize userID_len,
CK_ULONG *size )
{
PGPSize max_size = sizeof(certLabelPrefix)-1;
PGPByte *out, *p;
max_size += userID_len;
max_size += sizeof(certLabelSuffix)-1;
max_size += sKeyIDToString( keyID, NULL, TRUE );
p = out = malloc( max_size+sizeof('\0') );
if( out == NULL )
return NULL;
memcpy( p, certLabelPrefix, sizeof(certLabelPrefix)-1 );
p += sizeof(certLabelPrefix)-1;
memcpy( p, userID, userID_len );
p += userID_len;
memcpy( p, certLabelSuffix, sizeof(certLabelSuffix)-1 );
p += sizeof(certLabelSuffix)-1;
p += sKeyIDToString( keyID, p, TRUE );
*p = '\0';
*size = max_size;
return out;
}
/*
This is used to find PKCS11 objects using PKCS11 template.
templSize is the size of the templ in bytes
(therefore, use sizeof(templ)).
If in_buffer==NULL, then this function will malloc the handle buffer
and return it. Caller must free returned value in this case.
If the in_buffer is not NULL, then the function will fill this buffer
and return the pointer to this buffer.
*/
static CK_OBJECT_HANDLE *
sFindP11Objs( PGPToken *tptr,
const CK_ATTRIBUTE *searchTempl, int templSize, int *n,
CK_OBJECT_HANDLE *in_buffer, int in_buffer_n)
{
CK_RV rv;
const sizeSearch = templSize / sizeof(*searchTempl);
int howmany;
int n_handles = 2; /* average number of expected handles */
int n_handles_used=0;
void *to_free=NULL;
CK_OBJECT_HANDLE *handles = NULL;
*n = 0;
if (!tptr->have_session)
{
pgpDebugMsg( "sFindP11Objs called with no smartcard session" );
return NULL;
}
if( in_buffer == NULL ) {
to_free = handles = (CK_OBJECT_HANDLE*)calloc( sizeof(CK_OBJECT_HANDLE), n_handles );
if( handles == NULL )
return NULL;
}
rv = F->C_FindObjectsInit(tptr->session, (CK_ATTRIBUTE *)searchTempl, sizeSearch);
if (rv != CKR_OK)
{
pgpDebugMsg( "C_FindObjectsInit failed" );
free( to_free );
return NULL;
}
if( in_buffer == NULL ) { /* buffer is not specified */
pgpAssert( handles != NULL );
/* There is no way to know how many handles will be found in advance.
So we use the trial method. */
while(TRUE) {
howmany = 0;
rv = F->C_FindObjects(tptr->session, handles+n_handles_used, n_handles-n_handles_used, &howmany);
if (rv != CKR_OK) {
PGP_TOKEN_TRACE( "C_FindObjects failed" );
free( handles );
return NULL;
}
n_handles_used += howmany;
/* make sure we read all of them */
if( n_handles > n_handles_used )
break;
n_handles *= 2;
to_free = handles = realloc( handles, sizeof(CK_OBJECT_HANDLE)*n_handles );
if( to_free == NULL ) {
n_handles_used = 0;
break;
}
}
howmany = n_handles_used;
}
else { /* buffer is given */
handles = in_buffer;
rv = F->C_FindObjects(tptr->session, in_buffer, in_buffer_n, &howmany);
if (rv != CKR_OK)
{
pgpDebugMsg( "C_FindObjects failed" );
howmany = 0;
}
}
/* Always finalize */
rv = F->C_FindObjectsFinal(tptr->session);
if (rv != CKR_OK)
{
pgpDebugMsg( "C_FindObjectsFinal failed" );
free( to_free );
return NULL;
}
if( howmany == 0 ) {
free( to_free );
PGP_TOKEN_TRACE( "sFindP11Objs call returns NULL" );
return NULL;
}
PGP_TOKEN_TRACE1( "sFindP11Objs call returns with data: %d items", howmany );
*n = howmany;
return handles;
}
/*
Given PKCS11 object with CKA_ID attribute,
returns the handle to the related object, matching the 'templ'
of the 'size'.
We assume that input object and the object to be found are
'connected' by CKA_ID.
First row of the 'templ' must be the CKA_ID attribute.
Input object must have CKA_ID attribute.
First matched object will be returned.
output will have output->id and output->id_size initialized.
if templ consists of only CKA_ID, then output is the same as input with
resolved CKA_ID in 'id' field
*/
PGPBoolean static
sObjToRelatedObj( PGPToken *tptr,
const pgpTokenKeyInfoPriv *input,
CK_ATTRIBUTE *templ, int templ_size,
pgpTokenKeyInfoPriv *output )
{
CK_RV rv;
int howmany;
const PGPBoolean isID = ( input->id_size > 0 );
PGPByte *pID = (PGPByte *)( isID ? input->id : NULL );
int size = input->id_size;
memcpy( output, input, sizeof(*output) );
pgpAssert( !isID || input->id[0] );
pgpAssert( templ[0].type == CKA_ID );
pgpAssert( templ_size >= sizeof(templ[0]) );
if( !isID ) { /* ID is not specified, PKCS11 handle must */
CK_ATTRIBUTE pubTemplate[] = {
{ CKA_ID, NULL, 0 }
};
pgpAssert( size == 0 );
pgpAssert( input->handle );
rv = F->C_GetAttributeValue(tptr->session, input->handle, pubTemplate, 1);
if (rv != CKR_OK) {
pgpDebugMsg( "C_GetAttributeValue failed" );
return FALSE;
}
pID = malloc( pubTemplate[0].ulValueLen );
if( pID == NULL )
return FALSE;
size = pubTemplate[0].ulValueLen;
pubTemplate[0].pValue = pID;
rv = F->C_GetAttributeValue(tptr->session, input->handle, pubTemplate, 1);
if (rv != CKR_OK) {
free(pID);
pgpDebugMsg( "C_GetAttributeValue failed" );
return FALSE;
}
PGP_TOKEN_TRACE("sObjToRelatedObj: ID was not given");
}
#if PGP_DEBUG
else
PGP_TOKEN_TRACE("sObjToRelatedObj: ID was given");
#endif
/* Now we certainly know ID of the desired object */
if( templ_size > sizeof(templ[0]) ) { /* see if we need to find anything */
CK_OBJECT_HANDLE handle;
templ[0].pValue = (void*)pID;
templ[0].ulValueLen = size;
if( sFindP11Objs( tptr, templ, templ_size, &howmany, &handle, 1 ) == NULL )
{
PGP_TOKEN_TRACE( "sObjToRelatedObj: related object not found" );
if( !isID )
free( pID );
return FALSE;
}
pgpAssert( howmany == 1 );
output->handle = handle;
output->obj_class = CKO_PUBLIC_KEY;
if( size > sizeof(output->id) )
size = sizeof(output->id);
/* Store ID */
output->id_size = size;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -