📄 pgpp11key.c
字号:
/*____________________________________________________________________________
Copyright (C) 2002 PGP Corporation
All rights reserved.
$Id: pgpP11Key.c,v 1.80 2002/08/06 20:11:04 dallen Exp $
____________________________________________________________________________*/
#include "pgpSDKBuildFlags.h"
/* PKCS-11 (Cryptoki) Interface */
#include "pgpConfig.h"
#include <string.h>
#include <stddef.h>
#include "pgpDebug.h"
#include "pgpKeyMisc.h"
#include "pgpP11Key.h"
#include "pgpTokenLib.h"
#include "bn.h"
#include "pgpCFBPriv.h"
#include "pgpSymmetricCipherPriv.h"
#include "pgpHashPriv.h"
#include "pgpMem.h"
#include "pgpErrors.h"
#include "bnprime.h"
#include "pgpPubKey.h"
#include "pgpRandomX9_17.h"
#include "pgpStr2Key.h"
#include "pgpContext.h"
#include "pgpEnv.h"
#include "pgpKeyPriv.h"
#include "pgpX509Priv.h"
#include "pgpFIPSPriv.h"
#ifdef PGP_WIN32
#include "pgpPktByte.h"
#include "pgpEndianConversion.h"
#endif
/* Size of buffer to hold passphrase */
#define PASSBUFFERSIZE 80
/* Magic number at start of such buffers */
#define PASSBUFMAGIC 0x44201312
/* Mask to hide passphrase in cached buffers */
#define PASSBUFMASK 0x9D
/* A PGPSecKey's priv points to this */
/* This struct is always allocated using PGPNewSecureData */
typedef struct P11Sec
{
PGPContextRef context;
PGPToken *tok;
int locked;
BigNum mod; /* RSA Modulus */
PGPByte *cryptkey;
PGPSize cklen;
DEBUG_STRUCT_CONSTRUCTOR( P11secPlus )
} P11Sec ;
PGPByte sP11Module[255] = { '\0' };
#if PGP_WIN32
static PGPBoolean sHadTcl = FALSE;
/* PGPtcl library entry points */
static struct PGPtclEntries {
PGPError (*pgpTokenInit) (void);
PGPToken *(*pgpGetNthTokenObject) (PGPUInt32 n);
PGPToken *(*pgpGetTokenObjectByPrivKeyID) (const PGPByte *keyID);
PGPUInt32 (*pgpCountTokenObjects) (void);
PGPError (*pgpAcquireAllTokens) (void);
PGPError (*pgpReleaseAllTokens) (void);
PGPError (*pgpSetP11DllName)(const PGPByte *name);
PGPError ( *pgpFreeMem ) (void *p);
PGPInt32 (*pgpGetTokenNum)(PGPToken *token);
PGPError (*pgpSetCertToKeyID)( pgpTokenCertToKeyID f, void *param );
};
static struct PGPtclEntries F;
static inited = FALSE;
static HINSTANCE hTCL = NULL;
static sLoadTclTries = 0;
static int sCustomTcl = -1;
/* matches type pgpTokenCertToKeyID */
static PGPBoolean sCertToKeyID(
const PGPByte *cert, PGPSize size, PGPInputFormat obj_type, PGPByte id[8], PGPUInt32 *alg,
void *param )
{
PGPKeyDBRef db=NULL;
PGPContextRef context = (PGPContextRef)param;
PGPBoolean ret = FALSE;
pgpAssert( param != NULL );
pgpAssert( obj_type == kPGPInputFormat_PEMEncodedX509Cert ); /* programming errors */
if( param == NULL )
return FALSE;
memset( id, 0, 8 );
*alg = 0;
pgpDecodeX509Cert( (PGPByte *)cert, size, context, NULL, &db );
if( ! IsNull(db) ) {
PGPKeyDBObjRef key =
pgpFirstKeyInKeySet( PGPPeekKeyDBRootKeySet( db ) );
PGPKeyInfo *kinfo = pgpKeyToKeyInfo( key );
if( kinfo != NULL && kinfo->keyID != NULL ) {
memcpy( id, kinfo->keyID, 8 );
*alg = kinfo->pkalg;
ret = TRUE;
}
PGPFreeKeyDB( db );
}
return ret;
}
/* Load our PGPtcl(P11) library dynamically */
static void
sLoadTCL()
{
if( !inited && IsNull(hTCL) )
{
PGPBoolean is_generic = FALSE;
if( sCustomTcl == -1 ) { /* Try once to load custom TCL */
hTCL = LoadLibrary("PGPtcl");
if( IsNull(hTCL) ) {
sCustomTcl = 0;
inited = FALSE;
}
else {
#if PGP_DEBUG
OutputDebugString("sLoadTCL: custom TCL loaded (PGPtcl.dll)\n");
#endif
sCustomTcl = 1;
inited = TRUE;
}
}
if( ! inited ) {
if( sP11Module[0] != '\0' ) {
inited = TRUE; /* Tried -- no matter what the result */
hTCL = LoadLibrary("PGPtclP11");
if( IsntNull(hTCL) )
is_generic = TRUE;
}
}
if( IsntNull( hTCL ) )
{
memset( &F, 0, sizeof(F) );
F.pgpTokenInit = (void *)GetProcAddress( hTCL,
"pgpTokenInit" );
F.pgpGetNthTokenObject = (void *)GetProcAddress( hTCL,
"pgpGetNthTokenObject" );
F.pgpGetTokenObjectByPrivKeyID = (void *)GetProcAddress( hTCL,
"pgpGetTokenObjectByPrivKeyID" );
F.pgpCountTokenObjects = (void *)GetProcAddress( hTCL,
"pgpCountTokenObjects" );
F.pgpAcquireAllTokens = (void *)GetProcAddress( hTCL,
"pgpAcquireAllTokens" );
F.pgpReleaseAllTokens = (void *)GetProcAddress( hTCL,
"pgpReleaseAllTokens" );
F.pgpFreeMem = (void *)GetProcAddress( hTCL,
"pgpFreeMem" );
F.pgpGetTokenNum = (void *)GetProcAddress( hTCL,
"pgpGetTokenNum" );
F.pgpSetCertToKeyID = (void *)GetProcAddress( hTCL,
"pgpSetCertToKeyID" );
if( is_generic )
F.pgpSetP11DllName = (void *)GetProcAddress( hTCL,
"pgpSetP11DllName" );
if( IsNull( F.pgpTokenInit )
|| IsNull( F.pgpGetNthTokenObject )
|| IsNull( F.pgpGetTokenObjectByPrivKeyID )
|| IsNull( F.pgpCountTokenObjects )
|| IsNull( F.pgpAcquireAllTokens )
|| IsNull( F.pgpReleaseAllTokens )
|| IsNull( F.pgpFreeMem )
|| IsNull( F.pgpGetTokenNum )
|| ( is_generic && IsNull( F.pgpSetP11DllName )) )
{
/* Incompatible library version, pretend it didn't load */
FreeLibrary(hTCL);
hTCL = NULL;
memset( &F, 0, sizeof(F) );
} else {
pgpAssert( !is_generic || sP11Module[0] != '\0' );
if( is_generic && F.pgpSetP11DllName( sP11Module ) != kPGPError_NoErr ) {
#if PGP_DEBUG
OutputDebugString("PGPtclP11.pgpSetP11DllName() failed\n");
#endif
FreeLibrary(hTCL);
hTCL = NULL;
memset( &F, 0, sizeof(F) );
}
if( hTCL && F.pgpTokenInit() != kPGPError_NoErr ) {
#if PGP_DEBUG
OutputDebugString("PGPtclP11.pgpTokenInit() failed\n");
#endif
FreeLibrary(hTCL);
hTCL = NULL;
memset( &F, 0, sizeof(F) );
if( sLoadTclTries < 5 ) {
sLoadTclTries ++;
inited=FALSE; /* Give more tries */
}
#if PGP_DEBUG
else
OutputDebugString("PGPtclP11.pgpTokenInit() failed. No more tries\n");
#endif
}
}
}
}
}
#endif /* PGP_WIN32 */
#if PGP_WIN32
/*
Create PGP Public Key Packet V3/V4 from the keystub, RSA modulus and
public exponent.
Input size in bytes.
Caller must free the pkt_out.
*/
static PGPError
sPgpPubKeyPktFromRsa( PGPContextRef context,
const PGPByte *mod_buf, PGPSize mod_size,
const PGPByte *exp_buf, PGPSize exp_size,
const pgpTokenPubKeyStub *keyStub,
PGPByte **pkt_out, PGPSize *pkt_len_out )
{
#if PGP_WIN32
#pragma pack(push, cryptoki, 1)
#endif
struct RsaPktHdr {
PGPByte header; /* 0 offset */
PGPUInt16 total_len; /* 1 */
PGPByte ver; /* 3 */
PGPUInt32 time; /* 4 */
union {
PGPUInt16 expiration; /* 8 */
PGPByte alg_v4; /* 8 */
};
PGPByte alg_v3; /* 10 */
/* 11 */
};
struct RsaPktHdr *rsa_pkt_hdr;
#if PGP_WIN32
#pragma pack(pop, cryptoki)
#endif
const v = keyStub->flags & 0xf;
const struct_size = sizeof(struct RsaPktHdr) - ( v==PGPVERSION_3 ? 0 : 2/*no expiration*/ );
int total_size;
PGPByte *pkt_out_temp;
PGPByte *p;
PGPUInt16 size;
pgpAssert( mod_size < 0x10000 && exp_size < 0x10000 );
pgpAssert( keyStub && (keyStub->flags & 0x80) == 0 ); /* It can be full key later */
*pkt_out = NULL;
*pkt_len_out = 0;
while( *(PGPByte *)exp_buf == 0x00 && exp_size > 0 ) {
exp_buf++;
exp_size--;
}
total_size = mod_size+exp_size + struct_size + 2*sizeof(PGPUInt16)/*MPI length*/;
pkt_out_temp = (PGPByte*)pgpContextMemAlloc( context, total_size, 0 );
if( pkt_out_temp == NULL )
return kPGPError_OutOfMemory;
pgpAssert( v == PGPVERSION_3 || v == PGPVERSION_4 );
rsa_pkt_hdr = (struct RsaPktHdr *)pkt_out_temp;
size = total_size-sizeof(rsa_pkt_hdr->header)-sizeof(rsa_pkt_hdr->total_len);
rsa_pkt_hdr->header = PKTBYTE_BUILD( PKTBYTE_PUBKEY, 1/*two octet length*/ );
PGPUInt16ToEndian(size, kPGPBigEndian, (PGPByte*)&(rsa_pkt_hdr->total_len));
rsa_pkt_hdr->ver = v;
rsa_pkt_hdr->time = keyStub->creationtime;
if( v == PGPVERSION_3 ) {
rsa_pkt_hdr->alg_v3 = kPGPPublicKeyAlgorithm_RSA;
rsa_pkt_hdr->expiration = 0; /*never*/
}
else
rsa_pkt_hdr->alg_v4 = kPGPPublicKeyAlgorithm_RSA;
p = pkt_out_temp + struct_size;
size = mod_size * 8;
pgpAssert( *(PGPByte *)mod_buf & 0x80 );
PGPUInt16ToEndian(size, kPGPBigEndian, p); /* in bits */
p += sizeof(PGPUInt16);
pgpCopyMemory( mod_buf, p, mod_size );
p += mod_size;
size = exp_size * 8;
{ /* Determine the actual bit size */
int byte = *(PGPByte *)exp_buf; /* Highest byte */
if( byte == 0 ) {
PGPFreeData( pkt_out_temp );
return kPGPError_CorruptData;
}
while( (byte & 0x80) == 0 ) {
size --;
byte <<= 1;
}
}
PGPUInt16ToEndian(/*in*/size, kPGPBigEndian, /*out*/p); /* in bits */
p += sizeof(PGPUInt16);
pgpCopyMemory( exp_buf, p, exp_size );
*pkt_out = (PGPByte *)pkt_out_temp;
*pkt_len_out = total_size;
return kPGPError_NoErr;
}
#endif /* WIN32 */
#if PGP_WIN32
static PGPByte *
sPgpPubKeyPktFromDataInfo( PGPContextRef context, const pgpTokenDataInfo *di, PGPSize *size ) {
const PGPByte *e = (PGPByte*)(di+1);
const PGPByte *m = e + di->exp_size;
PGPByte *out;
sPgpPubKeyPktFromRsa( context, m, di->mod_size, e, di->exp_size,
&(di->pubKeyStub), &out, size );
return out;
}
#endif /* WIN32 */
/** Public key functions **/
/*
* Not implemented
*/
PGPPubKey *
p11PubFromBuf(
PGPContextRef context,
PGPByte const * buf,
PGPSize size,
PGPError * error)
{
(void) context;
(void) buf;
(void) size;
(void) error;
*error = kPGPError_PublicKeyUnimplemented;
return NULL;
}
/** Secret key functions **/
static void
p11SecDestroy(PGPSecKey *seckey)
{
P11Sec *sec = (P11Sec *)seckey->priv;
PGPContextRef context;
pgpAssertAddrValid( seckey, PGPSecKey );
context = seckey->context;
/* Make sure token is locked when we free it */
(void)pgpTokenObjDeAuth( sec->tok );
PGPFreeData( sec ); /* Wipes as it frees */
pgpClearMemory( seckey, sizeof(seckey));
pgpContextMemFree( context, seckey);
}
/*
* Generate a PGPPubKey from a PGPSecKey
*/
static PGPPubKey *
p11Pubkey(PGPSecKey const *seckey)
{
P11Sec *sec = (P11Sec *)seckey->priv;
PGPError error;
return pgpPubKeyFromBuf( seckey->context, seckey->pkAlg,
sec->cryptkey, sec->cklen, &error );
}
/*
* Set keyid
*/
static void
p11SecSetKeyID(PGPSecKey *seckey, PGPByte *keyid)
{
#if PGP_WIN32
P11Sec *sec = (P11Sec *)seckey->priv;
/* Change keyid on the token */
pgpTokenObjEditKeyList( sec->tok, seckey->keyID, keyid );
#endif
pgpCopyMemory(keyid, seckey->keyID, sizeof(seckey->keyID));
}
/*
* Yes, there *is* a reason that this is a function and no a variable.
* On a hardware device with an automatic timeout,
* it actually might need to do some work to find out.
*/
static int
p11Islocked(PGPSecKey const *seckey)
{
P11Sec const *sec = (P11Sec *)seckey->priv;
return sec->locked;
}
/*
* Return the algorithm and (symmetric) key size used for locking/unlocking
* the secret key.
* This is not possible with token keys, they are locked in hardware.
* We return a buffer size so that we can fake the passphrase conversion
*/
static PGPError
p11LockingAlgorithm(
PGPSecKey const *seckey,
PGPCipherAlgorithm *pAlg,
PGPSize *pAlgKeySize
)
{
(void) seckey;
if( IsntNull( pAlg ) )
*pAlg = kPGPCipherAlgorithm_None;
if( IsntNull( pAlgKeySize ) )
*pAlgKeySize = PASSBUFFERSIZE;
return kPGPError_NoErr;
}
/*
* Return the StringToKey type for unlocking the given key. We use
* kPGPStringToKey_Literal to flag a secret split unlocking buffer.
* Returns kPGPStringToKey_Simple if key has no passphrase.
*/
static PGPError
p11S2KType(
PGPSecKey const *seckey,
PGPStringToKeyType *s2kType
)
{
(void) seckey;
(void) s2kType;
return kPGPError_PublicKeyUnimplemented;
}
/* Recover passphrase from hashed version */
static PGPError
sRecoverHashedPhrase( PGPByte const *hphrase, PGPSize hphraseLen,
char *pphrase, PGPSize *pplen )
{
PGPByte mask = 0;
PGPSize plen;
if( hphraseLen < sizeof(PGPUInt32)+1
|| *(PGPUInt32 *)hphrase != PASSBUFMAGIC )
return kPGPError_BadPassphrase;
hphrase += sizeof( PGPUInt32 );
*pplen = plen = (PGPSize)*hphrase++;
while( plen-- )
*pphrase++ = *hphrase++ ^ (mask+=PASSBUFMASK);
return kPGPError_NoErr;
}
/*
* Convert a passphrase into a s2k literal buffer for the key.
* Returns error code. Output buffer will be size of the *pAlgKeySize
* parameter from pgpSecKeyLockingalgorithm.
* We store passphrase, preceded by length, lightly masked
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -