dbxpgp.c
来自「提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发」· C语言 代码 · 共 1,074 行 · 第 1/3 页
C
1,074 行
/* If it's an RSA key, read the components and set up the usage based on
the algorithm type */
if( value == PGP_ALGO_RSA || value == PGP_ALGO_RSA_ENCRYPT || \
value == PGP_ALGO_RSA_SIGN )
{
CRYPT_PKCINFO_RSA *rsaKeyPtr = &pgpInfo->key.rsaKey;
cryptInitComponents( rsaKeyPtr, isPublicKey ? \
CRYPT_KEYTYPE_PUBLIC : CRYPT_KEYTYPE_PRIVATE );
status = rsaKeyPtr->nLen = pgpReadMPI( stream, rsaKeyPtr->n );
if( !cryptStatusError( status ) )
status = rsaKeyPtr->eLen = pgpReadMPI( stream, rsaKeyPtr->e );
if( cryptStatusError( status ) )
return( status );
pgpInfo->pkcAlgo = CRYPT_ALGO_RSA;
if( value != PGP_ALGO_RSA_SIGN )
{
actionFlags |= MK_ACTION_PERM( RESOURCE_MESSAGE_CTX_ENCRYPT,
ACTION_PERM_NONE_EXTERNAL );
if( !isPublicKey )
actionFlags |= MK_ACTION_PERM( RESOURCE_MESSAGE_CTX_DECRYPT,
ACTION_PERM_NONE_EXTERNAL );
usageFlags = KEYMGMT_FLAG_USAGE_CRYPT;
}
if( value != PGP_ALGO_RSA_ENCRYPT )
{
actionFlags |= MK_ACTION_PERM( RESOURCE_MESSAGE_CTX_SIGCHECK,
ACTION_PERM_NONE_EXTERNAL );
if( !isPublicKey )
actionFlags |= MK_ACTION_PERM( RESOURCE_MESSAGE_CTX_SIGN,
ACTION_PERM_NONE_EXTERNAL );
usageFlags |= KEYMGMT_FLAG_USAGE_SIGN;
}
pgpInfo->actionFlags = actionFlags;
pgpInfo->usageFlags = usageFlags;
return( CRYPT_OK );
}
/* It's a DLP key, read the components and set the appropriate usage */
cryptInitComponents( dlpKeyPtr, isPublicKey ? \
CRYPT_KEYTYPE_PUBLIC : CRYPT_KEYTYPE_PRIVATE );
status = dlpKeyPtr->pLen = pgpReadMPI( stream, dlpKeyPtr->p );
if( !cryptStatusError( status ) )
if( value == PGP_ALGO_DSA )
status = dlpKeyPtr->qLen = pgpReadMPI( stream, dlpKeyPtr->q );
else
/* PGP Elgamal keys are PKCS #3 rather than FIPS 186-type DLP
keys and don't have a q component so we use an all-zero
value of 160 bits, the FIPS 186 standard size */
dlpKeyPtr->qLen = 160;
if( !cryptStatusError( status ) )
status = dlpKeyPtr->gLen = pgpReadMPI( stream, dlpKeyPtr->g );
if( !cryptStatusError( status ) )
status = dlpKeyPtr->yLen = pgpReadMPI( stream, dlpKeyPtr->y );
if( cryptStatusError( status ) )
return( status );
if( value == PGP_ALGO_DSA )
{
pgpInfo->pkcAlgo = CRYPT_ALGO_DSA;
actionFlags = MK_ACTION_PERM( RESOURCE_MESSAGE_CTX_SIGCHECK,
ACTION_PERM_NONE_EXTERNAL );
if( !isPublicKey )
actionFlags |= MK_ACTION_PERM( RESOURCE_MESSAGE_CTX_SIGN,
ACTION_PERM_NONE_EXTERNAL );
usageFlags = KEYMGMT_FLAG_USAGE_SIGN;
}
else
{
pgpInfo->pkcAlgo = CRYPT_ALGO_ELGAMAL;
actionFlags = MK_ACTION_PERM( RESOURCE_MESSAGE_CTX_ENCRYPT,
ACTION_PERM_NONE_EXTERNAL );
if( !isPublicKey )
actionFlags |= MK_ACTION_PERM( RESOURCE_MESSAGE_CTX_DECRYPT,
ACTION_PERM_NONE_EXTERNAL );
usageFlags = KEYMGMT_FLAG_USAGE_CRYPT;
}
pgpInfo->actionFlags = actionFlags;
pgpInfo->usageFlags = usageFlags;
return( CRYPT_OK );
}
/* Read private-key components. This gets somewhat complicated because
PGP 2.x encrypted only the MPI data while OpenPGP encrypts the entire
private key record, so for PGP 2.x we read and then decrypt, for OpenPGP
we decrypt and then read */
static int readCachedPrivateKeyComponents( PGP_INFO *pgpInfo,
const CRYPT_CONTEXT iCryptContext )
{
STREAM stream;
BYTE keyBuffer[ MAX_PRIVATE_KEYSIZE ];
WORD checkSum, packetChecksum;
const int keyDataLength = pgpInfo->cachedKeyLength - pgpInfo->privKeyStart;
int status;
/* Take a local copy of the private key data for the OpenPGP case where
we need to decrypt the entire record */
memcpy( keyBuffer, pgpInfo->cachedKey + pgpInfo->privKeyStart,
keyDataLength );
/* If it's OpenPGP, decrypt the private key record */
if( pgpInfo->isOpenPGP && pgpInfo->cryptAlgo != CRYPT_ALGO_NONE )
{
status = krnlSendMessage( iCryptContext,
RESOURCE_IMESSAGE_CTX_DECRYPT,
keyBuffer, keyDataLength );
if( cryptStatusError( status ) )
return( status );
}
/* Read the private key components and checksum */
sMemConnect( &stream, keyBuffer, keyDataLength );
if( pgpInfo->pkcAlgo == CRYPT_ALGO_RSA )
{
CRYPT_PKCINFO_RSA *rsaKeyPtr = &pgpInfo->key.rsaKey;
status = rsaKeyPtr->dLen = pgpReadMPI( &stream, rsaKeyPtr->d );
if( !cryptStatusError( status ) )
status = rsaKeyPtr->pLen = pgpReadMPI( &stream, rsaKeyPtr->p );
if( !cryptStatusError( status ) )
status = rsaKeyPtr->qLen = pgpReadMPI( &stream, rsaKeyPtr->q );
if( !cryptStatusError( status ) )
status = rsaKeyPtr->uLen = pgpReadMPI( &stream, rsaKeyPtr->u );
if( cryptStatusError( status ) )
return( status );
packetChecksum = ( sgetc( &stream ) << 8 ) | sgetc( &stream );
}
else
{
CRYPT_PKCINFO_DLP *dlpKeyPtr = &pgpInfo->key.dlpKey;
status = dlpKeyPtr->xLen = pgpReadMPI( &stream, dlpKeyPtr->x );
if( cryptStatusError( status ) )
return( status );
packetChecksum = ( sgetc( &stream ) << 8 ) | sgetc( &stream );
}
/* If it's PGP 2.x, decrypt the individual key fields */
if( !pgpInfo->isOpenPGP && pgpInfo->cryptAlgo != CRYPT_ALGO_NONE )
if( pgpInfo->pkcAlgo == CRYPT_ALGO_RSA )
{
CRYPT_PKCINFO_RSA *rsaKeyPtr = &pgpInfo->key.rsaKey;
krnlSendMessage( iCryptContext,
RESOURCE_IMESSAGE_CTX_DECRYPT,
rsaKeyPtr->d, bitsToBytes( rsaKeyPtr->dLen ) );
krnlSendMessage( iCryptContext,
RESOURCE_IMESSAGE_CTX_DECRYPT,
rsaKeyPtr->p, bitsToBytes( rsaKeyPtr->pLen ) );
krnlSendMessage( iCryptContext,
RESOURCE_IMESSAGE_CTX_DECRYPT,
rsaKeyPtr->q, bitsToBytes( rsaKeyPtr->qLen ) );
krnlSendMessage( iCryptContext,
RESOURCE_IMESSAGE_CTX_DECRYPT,
rsaKeyPtr->u, bitsToBytes( rsaKeyPtr->uLen ) );
}
else
{
CRYPT_PKCINFO_DLP *dlpKeyPtr = &pgpInfo->key.dlpKey;
krnlSendMessage( iCryptContext,
RESOURCE_IMESSAGE_CTX_DECRYPT,
dlpKeyPtr->x, bitsToBytes( dlpKeyPtr->xLen ) );
}
/* Make sure all was OK */
if( pgpInfo->pkcAlgo == CRYPT_ALGO_RSA )
{
CRYPT_PKCINFO_RSA *rsaKeyPtr = &pgpInfo->key.rsaKey;
checkSum = pgpChecksumMPI( rsaKeyPtr->d, rsaKeyPtr->dLen );
checkSum += pgpChecksumMPI( rsaKeyPtr->p, rsaKeyPtr->pLen );
checkSum += pgpChecksumMPI( rsaKeyPtr->q, rsaKeyPtr->qLen );
checkSum += pgpChecksumMPI( rsaKeyPtr->u, rsaKeyPtr->uLen );
}
else
{
CRYPT_PKCINFO_DLP *dlpKeyPtr = &pgpInfo->key.dlpKey;
checkSum = pgpChecksumMPI( dlpKeyPtr->x, dlpKeyPtr->xLen );
}
if( checkSum != packetChecksum )
return( ( pgpInfo->cryptAlgo != CRYPT_ALGO_NONE ) ? \
CRYPT_ERROR_WRONGKEY : CRYPT_ERROR_BADDATA );
return( CRYPT_OK );
}
/* Read a PGP user ID. This is somewhat more complex than a simple read
because OpenPGP introduced subkey packets which follow the main key and
are (implicitly) connected to the user ID for the main key, so we have to
keep track of whether we've already read a user ID for a main key and
associated it with any following subkeys if necessary */
static int readUserID( PGP_INFO *pgpInfo, STREAM *stream,
const CRYPT_KEYID_TYPE keyIDtype,
const void *keyID, const int keyIDlength,
const int flags )
{
BOOLEAN gotUserID = FALSE, foundKey = FALSE;
/* If we're searching by key ID, check whether this is the packet we
want. If it is, all we need to do is keep reading until we find a
user ID */
if( ( keyIDtype == CRYPT_IKEYID_KEYID || \
keyIDtype == CRYPT_IKEYID_PGPKEYID ) && \
matchKeyID( pgpInfo, keyID, keyIDlength,
( keyIDtype == CRYPT_IKEYID_PGPKEYID ) ? TRUE : FALSE ) )
foundKey = TRUE;
/* Read the userID packet(s). We also make sure we get at least one
userID if we've already got a match based on a key ID */
while( !foundKey || !gotUserID )
{
int ctb, length, i;
/* Skip keyring trust and signature packets. Packet type 61 is
something odd created by GPG which might be a DSA self-signature */
ctb = sgetc( stream );
while( getCTB( ctb ) == PGP_PACKET_TRUST || \
getCTB( ctb ) == PGP_PACKET_SIGNATURE || \
getCTB( ctb ) == 61 )
{
/* Skip the packet */
length = ( int ) pgpGetLength( stream, ctb );
sSkip( stream, length );
ctb = sgetc( stream );
}
/* We've reached the end of the current collection of key packets,
exit */
if( getCTB( ctb ) != PGP_PACKET_USERID )
{
sungetc( stream );
/* If we matched the key based on its key ID and we get here then
either there's no user ID present or it's been carried over
from an earlier key */
if( foundKey )
{
/* If there's no user ID present (ie this isn't a subkey with
the user ID carried carried over from the main key),
return a generic label */
if( !pgpInfo->userIDset )
strcpy( pgpInfo->userID,
"PGP private key (no user ID found)" );
return( CRYPT_OK );
}
/* If there's a previously-read user ID present and we're
matching by user ID but haven't found a match in the current
key packets, try a match with the previously-read ID */
if( pgpInfo->userIDset && \
( keyIDtype == CRYPT_KEYID_NAME || \
keyIDtype == CRYPT_KEYID_EMAIL ) && \
matchSubstring( ( char * ) keyID, keyIDlength,
pgpInfo->userID, strlen( pgpInfo->userID ),
pgpInfo->usageFlags, flags ) )
return( CRYPT_OK );
return( OK_SPECIAL );
}
/* Read the userID */
length = ( int ) pgpGetLength( stream, ctb );
for( i = 0; i < length && i < PGP_MAX_USERIDSIZE - 1; i++ )
pgpInfo->userID[ i ] = sgetc( stream );
pgpInfo->userID[ i ] = '\0';
pgpInfo->userIDset = TRUE;
if( i > length )
sSkip( stream, i - length );/* Skip excessively long userID */
gotUserID = TRUE;
/* Check if it's the one we want. If it's a key with subkeys and no
usage type is explicitly specified, this will always return the
main key. This is the best solution since the main key is always
a signing key which is more likely to be what the user wants.
Encryption keys will typically only be accessed via envelopes,
and the enveloping code can specify a preference of an
encryption-capable key, while signing keys will be read directly
and pushed into the envelope */
if( ( keyIDtype == CRYPT_KEYID_NAME || \
keyIDtype == CRYPT_KEYID_EMAIL ) && \
matchSubstring( ( char * ) keyID, keyIDlength,
pgpInfo->userID, strlen( pgpInfo->userID ),
pgpInfo->usageFlags, flags ) )
foundKey = TRUE;
}
return( CRYPT_OK );
}
/****************************************************************************
* *
* Read a Key *
* *
****************************************************************************/
/* Read a key and check whether it matches the required user ID */
static int readKey( PGP_INFO *pgpInfo, STREAM *stream,
const KEYMGMT_ITEM_TYPE itemType,
const CRYPT_KEYID_TYPE keyIDtype,
const void *keyID, const int keyIDlength,
const char *password, const int passwordLength,
void *keyData, int *keyDataLength, const int flags )
{
CRYPT_CONTEXT iCryptContext;
CRYPT_PKCINFO_RSA *rsaKeyPtr = &pgpInfo->key.rsaKey;
HASHFUNCTION hashFunction;
STREAM keyStream;
BYTE hashInfo[ MAX_HASHINFO_SIZE ];
BYTE packetHeader[ 64 ];
BOOLEAN isPublicKey = TRUE;
long endPos;
int hashSize, length, value, status;
/* If we're reading a non-cached key packet, skip the keyring headers and
read the key data into memory */
if( stream != NULL )
{
int ctb, status;
/* Skip CTB, packet length, and version byte. If we're reading a new
primary key, we clear the userID */
ctb = sgetc( stream );
switch( getCTB( ctb ) )
{
case PGP_PACKET_SECKEY:
pgpInfo->userIDset = FALSE;
/* Fall through */
case PGP_PACKET_SECKEY_SUB:
isPublicKey = FALSE;
break;
case PGP_PACKET_PUBKEY:
pgpInfo->userIDset = FALSE;
/* Fall through */
case PGP_PACKET_PUBKEY_SUB:
break;
default:
return( cryptStatusError( ctb ) ? \
CRYPT_ERROR_NOTFOUND : CRYPT_ERROR_BADDATA );
}
length = ( int ) pgpGetLength( stream, ctb );
endPos = ( int ) stell( stream ) + length;
value = sgetc( stream );
if( value != PGP_VERSION_2 && value != PGP_VERSION_3 && \
value != PGP_VERSION_OPENPGP )
{
/* Unknown version number, skip this packet */
skipToKeyPacket( stream, endPos );
return( OK_SPECIAL );
}
length -= 1 + 4;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?