📄 pgp_env.c
字号:
byte sigType
byte sigAlgo
byte hashAlgo
byte[2] length of auth.attributes
byte[] authenticated attributes
byte[2] length of unauth.attributes = 0
[ byte[2] hash check ]
[ mpi signature ]
PGP processes the authenticated attributes in an odd way, first hashing
part of the packet from the version number to the end of the authenticated
attributes, then some more stuff, and finally signing that. Because of
this complex way of handling things, we can't write the signature packet
in one go but instead have to write the part which is hashed, hash it, and
then go back and reassemble the whole thing from the pre-hashed data and
the length, hash check, and signature */
static int writeSignaturePacketHeader( void *dataBuffer, const int dataBufSize,
const CRYPT_CONTEXT iSignContext,
const CRYPT_CONTEXT iHashContext,
const int iAndSlength )
{
CRYPT_ALGO hashAlgo, signAlgo;
STREAM stream;
RESOURCE_DATA msgData;
BYTE keyID[ PGP_KEYID_SIZE ];
BYTE iAndSHeader[ 64 ];
BYTE buffer[ 8 ], *bufPtr = buffer;
time_t theTime = time( NULL );
static const char *nameString = "issuerAndSerialNumber";
int length, iAndSHeaderLength = 0, status;
/* Get the signature information */
status = krnlSendMessage( iHashContext, RESOURCE_IMESSAGE_GETATTRIBUTE,
&hashAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iSignContext,
RESOURCE_IMESSAGE_GETATTRIBUTE, &signAlgo,
CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
{
setResourceData( &msgData, keyID, PGP_KEYID_SIZE );
status = krnlSendMessage( iSignContext,
RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_OPENPGP_KEYID );
}
if( cryptStatusError( status ) )
return( status );
/* Write the issuerAndSerialNumber packet header if necessary:
byte[4] flags = 0
byte[2] typeLength
byte[2] valueLength
byte[] type
byte[] value
Since this is a variable-length packet we need to pre-encode it
before we can write the main packet data */
if( iAndSlength )
{
STREAM headerStream;
sMemOpen( &headerStream, iAndSHeader, 64 );
writePacketHeader( &headerStream, 0, 1 + 4 + 2 + 2 + \
strlen( nameString ) + iAndSlength );
sputc( &headerStream, PGP_SUBPACKET_TYPEANDVALUE );
swrite( &headerStream, "\x00\x00\x00\x00", 4 );
sputc( &headerStream, 0 );
sputc( &headerStream, strlen( nameString ) );
sputc( &headerStream, ( iAndSlength >> 8 ) & 0xFF );
sputc( &headerStream, iAndSlength & 0xFF );
swrite( &headerStream, nameString, strlen( nameString ) );
iAndSHeaderLength = ( int ) stell( &headerStream );
assert( sStatusOK( &headerStream ) );
sMemDisconnect( &headerStream );
}
/* Write the general header information */
sMemOpen( &stream, dataBuffer, dataBufSize );
sputc( &stream, 4 ); /* Version = 4 (OpenPGP) */
sputc( &stream, 0 ); /* Binary document sig. */
sputc( &stream, ( signAlgo == CRYPT_ALGO_RSA ) ? \
PGP_ALGO_RSA : PGP_ALGO_DSA );
writeHashAlgorithmID( &stream, hashAlgo );
/* Write the authenticated attributes. The signer ID is optional, but
if we omit it GPG fails the signature check so we always include it */
length = 1 + 1 + 4 + 1 + 1 + PGP_KEYID_SIZE;
if( iAndSlength )
length += iAndSHeaderLength + iAndSlength;
sputc( &stream, ( length >> 8 ) & 0xFF );
sputc( &stream, length & 0xFF );
sputc( &stream, 1 + 4 );
sputc( &stream, PGP_SUBPACKET_TIME );
mputBLong( bufPtr, theTime );
swrite( &stream, buffer, 4 );
sputc( &stream, 1 + PGP_KEYID_SIZE );
sputc( &stream, PGP_SUBPACKET_KEYID );
swrite( &stream, keyID, PGP_KEYID_SIZE );
if( iAndSlength )
{
swrite( &stream, iAndSHeader, iAndSHeaderLength );
setResourceData( &msgData, sMemBufPtr( &stream ),
sMemDataLeft( &stream ) - 2 );
status = krnlSendMessage( iSignContext,
RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
if( cryptStatusError( status ) )
{
sMemClose( &stream );
return( status );
}
sSkip( &stream, msgData.length );
}
/* Write the unauthenticated attributes */
sputc( &stream, 0 );
status = sputc( &stream, 0 );
/* Clean up */
length = ( int ) stell( &stream );
sMemDisconnect( &stream );
return( cryptStatusError( status ) ? status : length );
}
/****************************************************************************
* *
* Envelope Pre/Post-processing Functions *
* *
****************************************************************************/
/* The following functions take care of pre/post-processing of envelope data
during the enveloping process */
static int preEnvelopeEncrypt( ENVELOPE_INFO *envelopeInfoPtr )
{
CRYPT_DEVICE iCryptDevice = CRYPT_ERROR;
ACTION_LIST *actionListPtr;
int status;
/* Create the session key if necessary */
if( envelopeInfoPtr->actionList == NULL )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
int status;
/* Create a default encryption action and add it to the action
list */
setMessageCreateObjectInfo( &createInfo,
envelopeInfoPtr->defaultAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CONTEXT );
if( cryptStatusOK( status ) )
{
static const CRYPT_MODE mode = CRYPT_MODE_CFB;
krnlSendMessage( createInfo.cryptHandle,
RESOURCE_IMESSAGE_SETATTRIBUTE,
( void * ) &mode, CRYPT_CTXINFO_MODE );
status = krnlSendMessage( createInfo.cryptHandle,
RESOURCE_IMESSAGE_CTX_GENKEY,
NULL, FALSE );
if( cryptStatusOK( status ) && \
addAction( &envelopeInfoPtr->actionList, ACTION_CRYPT,
createInfo.cryptHandle ) == NULL )
status = CRYPT_ERROR_MEMORY;
if( cryptStatusError( status ) )
krnlSendNotifier( createInfo.cryptHandle,
RESOURCE_IMESSAGE_DECREFCOUNT );
}
if( cryptStatusError( status ) )
return( status );
}
else
{
/* If the session key context is tied to a device, get its handle so
we can check that all key exchange objects are also in the same
device */
status = krnlSendMessage( envelopeInfoPtr->actionList->iCryptHandle,
RESOURCE_MESSAGE_GETDEPENDENT,
&iCryptDevice, OBJECT_TYPE_DEVICE );
if( cryptStatusError( status ) )
iCryptDevice = CRYPT_ERROR;
}
/* Notify the kernel that the session key context is attached to the
envelope. This is an internal object used only by the envelope so we
tell the kernel not to increment its reference count when it attaches
it */
krnlSendMessage( envelopeInfoPtr->objectHandle,
RESOURCE_IMESSAGE_SETDEPENDENT,
&envelopeInfoPtr->actionList->iCryptHandle,
SETDEP_OPTION_NOINCREF );
/* Now walk down the list of key exchange actions connecting each one to
the session key action */
for( actionListPtr = findAction( envelopeInfoPtr->preActionList,
ACTION_KEYEXCHANGE_PKC );
actionListPtr != NULL && \
actionListPtr->action == ACTION_KEYEXCHANGE_PKC;
actionListPtr = actionListPtr->next )
{
/* If the session key context is tied to a device, make sure the key
exchange object is in the same device */
if( iCryptDevice != CRYPT_ERROR )
{
CRYPT_DEVICE iKeyexDevice;
status = krnlSendMessage( actionListPtr->iCryptHandle,
RESOURCE_MESSAGE_GETDEPENDENT,
&iKeyexDevice, OBJECT_TYPE_DEVICE );
if( cryptStatusError( status ) || iCryptDevice != iKeyexDevice )
return( CRYPT_ERROR_INVALID );
}
/* Remember that we now have a controlling action and connect the
controller to the subject */
envelopeInfoPtr->actionList->needsController = FALSE;
actionListPtr->associatedAction = envelopeInfoPtr->actionList;
}
return( CRYPT_OK );
}
/****************************************************************************
* *
* Emit Envelope Preamble/Postamble *
* *
****************************************************************************/
/* Output as much of the preamble as possible into the envelope buffer */
static int emitPreamble( ENVELOPE_INFO *envelopeInfoPtr )
{
PGP_ENV_STATE state = envelopeInfoPtr->pgpEnvState;
int status = CRYPT_OK;
/* If there's any data left in the auxiliary buffer, try and empty that
first */
if( envelopeInfoPtr->auxBufPos && copyFromAuxBuffer( envelopeInfoPtr ) )
return( CRYPT_ERROR_OVERFLOW );
/* If we've finished processing the header information, don't do
anything */
if( state == PGP_ENVSTATE_DONE )
return( CRYPT_OK );
/* If we haven't started doing anything yet, perform various final
initialisations */
if( state == PGP_ENVSTATE_NONE )
{
/* If there's no nested content type set, default to plain data */
if( envelopeInfoPtr->contentType == CRYPT_CONTENT_NONE )
envelopeInfoPtr->contentType = CRYPT_CONTENT_DATA;
/* Perform any remaining initialisation. Since PGP derives the
session key directly from the user password, we only perform this
initialisation if there are PKC key exchange actions present */
if( envelopeInfoPtr->usage == ACTION_CRYPT && \
findAction( envelopeInfoPtr->preActionList,
ACTION_KEYEXCHANGE_PKC ) != NULL )
status = preEnvelopeEncrypt( envelopeInfoPtr );
if( cryptStatusError( status ) )
return( status );
/* Delete any orphaned actions (for example automatically added
hash actions which were overridden with user-supplied alternate
actions) */
deleteUnusedActions( envelopeInfoPtr );
/* We're ready to go, connect a write stream to the auxBuffer and
prepare to emit the outer header */
sMemOpen( &envelopeInfoPtr->auxStream, envelopeInfoPtr->auxBuffer,
envelopeInfoPtr->auxBufSize );
state = PGP_ENVSTATE_HEADER;
assert( actionsOK( envelopeInfoPtr ) );
}
/* Emit the outer header */
if( state == PGP_ENVSTATE_HEADER )
{
STREAM stream;
/* If we're encrypting, set up the encryption-related information.
Since PGP doesn't perform a key exchange of a session key when
conventionally-encrypting data, the encryption information could
be coming from either an encryption action (derived from a
password) or a conventional key exchange action which results in
the direct creation of a session encryption key */
if( envelopeInfoPtr->usage == ACTION_CRYPT )
{
status = initEnvelopeEncryption( envelopeInfoPtr,
envelopeInfoPtr->actionList->iCryptHandle,
CRYPT_UNUSED, CRYPT_UNUSED, NULL, 0, FALSE );
if( cryptStatusError( status ) )
return( status );
/* Prepare to start emitting the key exchange (PKC-encrypted) or
session key (conventionally encrypted) actions */
envelopeInfoPtr->lastAction = \
findAction( envelopeInfoPtr->preActionList,
ACTION_KEYEXCHANGE_PKC );
if( envelopeInfoPtr->lastAction == NULL )
envelopeInfoPtr->lastAction = envelopeInfoPtr->actionList;
state = PGP_ENVSTATE_KEYINFO;
}
else
{
/* If we're not encrypting data (ie there's only a single packet
present) write the appropriate PGP header based on the
envelope usage. Since this is the first data written, we can
write it directly to the envelope buffer without having to go
via the auxBuffer */
sMemOpen( &stream, envelopeInfoPtr->buffer, envelopeInfoPtr->bufSize );
switch( envelopeInfoPtr->usage )
{
case ACTION_SIGN:
status = writeSignatureInfoPacket( &stream,
envelopeInfoPtr->postActionList->iCryptHandle,
envelopeInfoPtr->actionList->iCryptHandle );
if( cryptStatusError( status ) )
break;
/* Since we can only sign literal data, we need to
explicitly write an inner data header */
assert( envelopeInfoPtr->contentType == CRYPT_CONTENT_DATA );
state = PGP_ENVSTATE_DATA;
break;
case ACTION_NONE:
/* Write the header followed by an indicator that we're
using opaque content, a zero-length filename, and no
date */
writePacketHeader( &stream, PGP_PACKET_DATA,
envelopeInfoPtr->payloadSize + PGP_DATA_HEADER_SIZE );
swrite( &stream, "b\x00\x00\x00\x00\x00",
PGP_DATA_HEADER_SIZE );
break;
case ACTION_COMPRESS:
writePacketHeader( &stream, PGP_PACKET_COPR,
envelopeInfoPtr->payloadSize );
sputc( &stream, PGP_ALGO_ZLIB );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -