📄 pgp_env.c
字号:
if( cryptStatusError( status ) )
{
krnlSendNotifier( iSessionKeyContext, IMESSAGE_DECREFCOUNT );
return( status );
}
/* Add the session-key action to the action list */
status = addAction( &envelopeInfoPtr->actionList,
envelopeInfoPtr->memPoolState, ACTION_CRYPT,
iSessionKeyContext );
if( cryptStatusError( status ) )
{
krnlSendNotifier( iSessionKeyContext, IMESSAGE_DECREFCOUNT );
return( status );
}
return( CRYPT_OK );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int preEnvelopeEncrypt( INOUT ENVELOPE_INFO *envelopeInfoPtr )
{
CRYPT_DEVICE iCryptDevice = CRYPT_ERROR;
ACTION_LIST *actionListPtr;
int iterationCount, status;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
REQUIRES( envelopeInfoPtr->usage == ACTION_CRYPT );
REQUIRES( findAction( envelopeInfoPtr->preActionList, \
ACTION_KEYEXCHANGE_PKC ) != NULL );
/* Create the session key if necessary */
if( envelopeInfoPtr->actionList == NULL )
{
status = createSessionKey( envelopeInfoPtr );
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,
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 */
status = krnlSendMessage( envelopeInfoPtr->objectHandle,
IMESSAGE_SETDEPENDENT,
&envelopeInfoPtr->actionList->iCryptHandle,
SETDEP_OPTION_NOINCREF );
if( cryptStatusError( status ) )
return( status );
/* Now walk down the list of key exchange actions connecting each one to
the session key action. The caller has already guaranteed that there's
at least one PKC keyex action present */
for( actionListPtr = findAction( envelopeInfoPtr->preActionList,
ACTION_KEYEXCHANGE_PKC ), \
iterationCount = 0;
actionListPtr != NULL && \
actionListPtr->action == ACTION_KEYEXCHANGE_PKC && \
iterationCount < FAILSAFE_ITERATIONS_MED;
actionListPtr = actionListPtr->next, iterationCount++ )
{
/* If the session key context is tied to a device, make sure that
the key exchange object is in the same device */
if( iCryptDevice != CRYPT_ERROR )
{
CRYPT_DEVICE iKeyexDevice;
status = krnlSendMessage( actionListPtr->iCryptHandle,
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->flags &= ~ACTION_NEEDSCONTROLLER;
actionListPtr->associatedAction = envelopeInfoPtr->actionList;
/* Evaluate the size of the exported action. We only get PKC
actions at this point so we don't have to provide any special-
case handling for other key exchange types */
status = iCryptExportKey( NULL, 0, &actionListPtr->encodedSize,
CRYPT_FORMAT_PGP,
envelopeInfoPtr->actionList->iCryptHandle,
actionListPtr->iCryptHandle );
if( cryptStatusError( status ) )
return( status );
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
return( CRYPT_OK );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int preEnvelopeSign( const ENVELOPE_INFO *envelopeInfoPtr )
{
ACTION_LIST *actionListPtr = envelopeInfoPtr->postActionList;
assert( isReadPtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
REQUIRES( envelopeInfoPtr->usage == ACTION_SIGN );
/* Make sure that there's at least one signing action present */
if( actionListPtr == NULL )
return( CRYPT_ERROR_NOTINITED );
assert( isWritePtr( actionListPtr, sizeof( ACTION_LIST ) ) );
REQUIRES( actionListPtr->associatedAction != NULL );
/* Evaluate the size of the signature action */
return( iCryptCreateSignature( NULL, 0, &actionListPtr->encodedSize,
CRYPT_FORMAT_PGP, actionListPtr->iCryptHandle,
actionListPtr->associatedAction->iCryptHandle,
CRYPT_UNUSED, CRYPT_UNUSED ) );
}
/****************************************************************************
* *
* Emit Envelope Preamble/Postamble *
* *
****************************************************************************/
/* Output as much of the preamble as possible into the envelope buffer */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int emitPreamble( INOUT ENVELOPE_INFO *envelopeInfoPtr )
{
int status = CRYPT_OK;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
REQUIRES( sanityCheck( envelopeInfoPtr ) );
/* If we've finished processing the header information, don't do
anything */
if( envelopeInfoPtr->envState == ENVSTATE_DONE )
return( CRYPT_OK );
/* If we haven't started doing anything yet, perform various final
initialisations */
if( envelopeInfoPtr->envState == 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;
/* If there's an absolute data length set, remember it for when we
copy in data */
if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
envelopeInfoPtr->segmentSize = envelopeInfoPtr->payloadSize;
/* Perform any remaining initialisation. Since PGP derives the
session key directly from the user password we only perform the
encryption initialisation if there are PKC key exchange actions
present */
if( envelopeInfoPtr->usage == ACTION_CRYPT && \
findAction( envelopeInfoPtr->preActionList,
ACTION_KEYEXCHANGE_PKC ) != NULL )
status = preEnvelopeEncrypt( envelopeInfoPtr );
else
{
if( envelopeInfoPtr->usage == ACTION_SIGN )
status = preEnvelopeSign( envelopeInfoPtr );
}
if( cryptStatusError( status ) )
{
retExt( status,
( status, ENVELOPE_ERRINFO,
"Couldn't perform final %s initialisation prior to "
"enveloping data",
( envelopeInfoPtr->usage == ACTION_SIGN ) ? \
"signing" : "encryption" ) );
}
/* Delete any orphaned actions such as automatically-added hash
actions that were overridden with user-supplied alternate
actions */
deleteUnusedActions( envelopeInfoPtr );
/* We're ready to go, prepare to emit the outer header */
envelopeInfoPtr->envState = ENVSTATE_HEADER;
ENSURES( checkActions( envelopeInfoPtr ) );
}
/* Emit the outer header. This always follows directly from the final
initialisation step but we keep the two logically distinct to
emphasise the fact that the former is merely finalised enveloping
actions without performing any header processing while the latter is
the first stage that actually emits header data */
if( envelopeInfoPtr->envState == ENVSTATE_HEADER )
{
status = writeHeaderPacket( envelopeInfoPtr );
if( cryptStatusError( status ) )
{
retExt( status,
( status, ENVELOPE_ERRINFO,
"Couldn't create envelope header" ) );
}
}
/* Handle key export actions */
if( envelopeInfoPtr->envState == ENVSTATE_KEYINFO )
{
status = writeKeyex( envelopeInfoPtr );
if( cryptStatusError( status ) )
{
retExt( status,
( status, ENVELOPE_ERRINFO,
"Couldn't emit key exchange actions to envelope "
"header" ) );
}
/* Move on to the next state */
envelopeInfoPtr->envState = ENVSTATE_ENCRINFO;
}
/* Handle encrypted content information */
if( envelopeInfoPtr->envState == ENVSTATE_ENCRINFO )
{
/* Write the encrypted content header */
status = writeEncryptedContentHeader( envelopeInfoPtr );
if( cryptStatusError( status ) )
{
retExt( status,
( status, ENVELOPE_ERRINFO,
"Couldn't emit encrypted content header to envelope "
"header" ) );
}
/* Make sure that we start a new segment if we try to add any data */
envelopeInfoPtr->dataFlags |= ENVDATA_SEGMENTCOMPLETE;
/* Before we can finish we have to push in the inner data header */
envelopeInfoPtr->envState = ENVSTATE_DATA;
}
/* Handle data payload information */
if( envelopeInfoPtr->envState == ENVSTATE_DATA )
{
STREAM stream;
BYTE headerBuffer[ 64 + 8 ];
/* Make sure that there's enough room to emit the data header (+8
for slop space) */
if( envelopeInfoPtr->bufPos + PGP_MAX_HEADER_SIZE + \
PGP_DATA_HEADER_SIZE + 8 >= envelopeInfoPtr->bufSize )
return( CRYPT_ERROR_OVERFLOW );
/* Write the payload header. Since this may be encrypted we have to
do it indirectly via copyToEnvelope() */
sMemOpen( &stream, headerBuffer, 64 );
pgpWritePacketHeader( &stream, PGP_PACKET_DATA,
PGP_DATA_HEADER_SIZE + envelopeInfoPtr->payloadSize );
status = swrite( &stream, PGP_DATA_HEADER, PGP_DATA_HEADER_SIZE );
if( cryptStatusOK( status ) && \
envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
{
/* There's an absolute data length set, adjust the running total
count by the size of the additional header that's been
prepended */
envelopeInfoPtr->segmentSize += stell( &stream );
}
if( cryptStatusOK( status ) )
status = envelopeInfoPtr->copyToEnvelopeFunction( envelopeInfoPtr,
headerBuffer, stell( &stream ) );
sMemClose( &stream );
if( cryptStatusError( status ) )
{
retExt( status,
( status, ENVELOPE_ERRINFO,
"Couldn't emit data header into envelope header" ) );
}
/* We've processed the header, if this is signed data we start
hashing from this point. The PGP RFCs are wrong in this regard
in that only the payload is hashed and not the entire packet */
if( envelopeInfoPtr->usage == ACTION_SIGN )
envelopeInfoPtr->dataFlags |= ENVDATA_HASHACTIONSACTIVE;
/* We're finished */
envelopeInfoPtr->envState = ENVSTATE_DONE;
}
ENSURES( sanityCheck( envelopeInfoPtr ) );
return( CRYPT_OK );
}
/* Output as much of the postamble as possible into the envelope buffer */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int emitPostamble( INOUT ENVELOPE_INFO *envelopeInfoPtr )
{
int sigBufSize, sigSize, status;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
REQUIRES( sanityCheck( envelopeInfoPtr ) );
/* Before we can emit the trailer we need to flush any remaining data
from internal buffers */
if( envelopeInfoPtr->envState == ENVSTATE_NONE )
{
status = envelopeInfoPtr->copyToEnvelopeFunction( envelopeInfoPtr,
( BYTE * ) "", 0 );
if( cryptStatusError( status ) )
{
retExt( status,
( status, ENVELOPE_ERRINFO,
"Couldn't flush remaining data into envelope "
"buffer" ) );
}
envelopeInfoPtr->envState = ENVSTATE_FLUSHED;
}
/* The only PGP packet that has a trailer is signed data using the new
(post-2.x) one-pass signature packet, if we're not signing data we can
exit now */
if( envelopeInfoPtr->usage != ACTION_SIGN )
{
/* We're done */
envelopeInfoPtr->envState = ENVSTATE_DONE;
ENSURES( sanityCheck( envelopeInfoPtr ) );
return( CRYPT_OK );
}
/* Check whether there's enough room left in the buffer to emit the
signature directly into it. Since signatures are fairly small (a few
hundred bytes) we always require enough room in the buffer and don't
bother with any overflow handling via the auxBuffer */
sigBufSize = min( envelopeInfoPtr->bufSize - envelopeInfoPtr->bufPos,
MAX_INTLENGTH_SHORT - 1 );
if( envelopeInfoPtr->postActionList->encodedSize + 64 > sigBufSize )
return( CRYPT_ERROR_OVERFLOW );
/* Sign the data */
status = iCryptCreateSignature( envelopeInfoPtr->buffer + \
envelopeInfoPtr->bufPos, sigBufSize, &sigSize,
CRYPT_FORMAT_PGP,
envelopeInfoPtr->postActionList->iCryptHandle,
envelopeInfoPtr->actionList->iCryptHandle, CRYPT_UNUSED,
CRYPT_UNUSED );
if( cryptStatusError( status ) )
{
retExt( status,
( status, ENVELOPE_ERRINFO,
"Couldn't emit signature to envelope trailer" ) );
}
envelopeInfoPtr->bufPos += sigSize;
/* Now that we've written the final data, set the end-of-segment-data
pointer to the end of the data in the buffer so that
copyFromEnvelope() can copy out the remaining data */
envelopeInfoPtr->segmentDataEnd = envelopeInfoPtr->bufPos;
envelopeInfoPtr->envState = ENVSTATE_DONE;
ENSURES( sanityCheck( envelopeInfoPtr ) );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Envelope Access Routines *
* *
****************************************************************************/
STDC_NONNULL_ARG( ( 1 ) ) \
void initPGPEnveloping( INOUT ENVELOPE_INFO *envelopeInfoPtr )
{
int dummy, status;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
REQUIRES_V( !( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) );
/* Set the access method pointers */
envelopeInfoPtr->processPreambleFunction = emitPreamble;
envelopeInfoPtr->processPostambleFunction = emitPostamble;
envelopeInfoPtr->checkAlgo = pgpCheckAlgo;
/* Set up the processing state information */
envelopeInfoPtr->envState = ENVSTATE_NONE;
/* Remember the current default settings for use with the envelope.
Since the PGP algorithms represent only a subset of what's available
we have to drop back to fixed values if the caller has selected
something exotic */
status = krnlSendMessage( envelopeInfoPtr->ownerHandle,
IMESSAGE_GETATTRIBUTE,
&envelopeInfoPtr->defaultHash,
CRYPT_OPTION_ENCR_HASH );
if( cryptStatusError( status ) || \
cryptStatusError( \
cryptlibToPgpAlgo( envelopeInfoPtr->defaultHash, &dummy ) ) )
envelopeInfoPtr->defaultHash = CRYPT_ALGO_SHA1;
status = krnlSendMessage( envelopeInfoPtr->ownerHandle,
IMESSAGE_GETATTRIBUTE,
&envelopeInfoPtr->defaultAlgo,
CRYPT_OPTION_ENCR_ALGO );
if( cryptStatusError( status ) || \
cryptStatusError( \
cryptlibToPgpAlgo( envelopeInfoPtr->defaultAlgo, &dummy ) ) )
envelopeInfoPtr->defaultAlgo = CRYPT_ALGO_3DES;
envelopeInfoPtr->defaultMAC = CRYPT_ALGO_NONE;
/* Turn off segmentation of the envelope payload. PGP has a single
length at the start of the data and doesn't segment the payload */
envelopeInfoPtr->dataFlags |= ENVDATA_NOSEGMENT;
}
#endif /* USE_PGP */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -