📄 pgp_env.c
字号:
if( envelopeInfoPtr->contentType == CRYPT_CONTENT_DATA )
/* If there's no inner content type, we need to
explicitly write an inner data header */
state = PGP_ENVSTATE_DATA;
break;
default:
assert( NOTREACHED );
}
envelopeInfoPtr->bufPos = ( int ) stell( &stream );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
return( status );
/* Reset the segmentation state (although PGP doesn't segment the
payload, we still need to reset the state to synchronise
things like payload hashing and encryption) and set the block
size mask to all ones if we're not encrypting (since we can
begin and end data segments on arbitrary boundaries) */
envelopeInfoPtr->segmentComplete = TRUE;
if( envelopeInfoPtr->usage != ACTION_CRYPT )
envelopeInfoPtr->blockSizeMask = -1;
envelopeInfoPtr->lastAction = NULL;
/* If we're not emitting any inner header, we're done */
if( state == PGP_ENVSTATE_HEADER )
state = PGP_ENVSTATE_DONE;
}
}
/* Keep producing output until we fill the envelope buffer or run out of
header information to encode */
while( state != PGP_ENVSTATE_DONE )
{
/* Handle key export actions */
if( state == PGP_ENVSTATE_KEYINFO )
{
ACTION_LIST *lastActionPtr = envelopeInfoPtr->lastAction;
/* Export the session key using each of the PKC keys, or
write the derivation information needed to recreate the
session key */
while( cryptStatusOK( status ) && lastActionPtr != NULL )
{
if( lastActionPtr->action == ACTION_KEYEXCHANGE_PKC )
status = writePKEPacket( &envelopeInfoPtr->auxStream,
envelopeInfoPtr->iCryptContext,
lastActionPtr->iCryptHandle );
else
status = writeSKEPacket( &envelopeInfoPtr->auxStream,
lastActionPtr->iCryptHandle );
if( !cryptStatusError( status ) )
{
lastActionPtr = lastActionPtr->next;
if( copyFromAuxStream( envelopeInfoPtr ) )
status = CRYPT_ERROR_OVERFLOW;
}
}
envelopeInfoPtr->lastAction = lastActionPtr;
/* If we've reached the last key exchange action, move on to the
next state. Since the emission of the key exchange
information is interruptible, we only move on to the next
state if there are no errors */
if( cryptStatusError( status ) )
break;
state = PGP_ENVSTATE_ENCRINFO;
}
/* Handle encrypted content information */
if( state == PGP_ENVSTATE_ENCRINFO )
{
BYTE ivInfoBuffer[ CRYPT_MAX_IVSIZE + 2 ];
/* Set up the PGP IV information */
status = pgpProcessIV( envelopeInfoPtr->iCryptContext,
ivInfoBuffer, PGP_IVSIZE, TRUE, TRUE );
if( cryptStatusError( status ) )
break;
/* Write the encrypted content header */
status = writePacketHeader( &envelopeInfoPtr->auxStream,
PGP_PACKET_ENCR, PGP_IVSIZE + 2 + \
sizeofPacketHeader( PGP_DATA_HEADER_SIZE + \
envelopeInfoPtr->payloadSize ) + \
PGP_DATA_HEADER_SIZE + envelopeInfoPtr->payloadSize );
if( cryptStatusOK( status ) )
status = swrite( &envelopeInfoPtr->auxStream, ivInfoBuffer,
PGP_IVSIZE + 2 );
if( cryptStatusOK( status ) && \
copyFromAuxStream( envelopeInfoPtr ) )
status = CRYPT_ERROR_OVERFLOW;
if( cryptStatusError( status ) )
break;
/* Make sure we start a new segment if we try to add any data */
envelopeInfoPtr->segmentComplete = TRUE;
/* Before we can finish we have to push in the inner data
header */
state = PGP_ENVSTATE_DATA;
}
/* Handle data payload information */
if( state == PGP_ENVSTATE_DATA )
{
STREAM headerStream;
BYTE headerBuffer[ 64 ];
/* Write the inner data header. This is part of the processed
payload so we can't copy it to the auxiliary stream but have
to use copyToEnvelope(). Since recovering from a partial copy
is a bit tricky, we first make sure there's enough room left
to copy in the header */
if( envelopeInfoPtr->bufSize - envelopeInfoPtr->bufPos < 16 )
{
status = CRYPT_ERROR_OVERFLOW;
break;
}
/* There's enough room for the header, copy it in */
sMemOpen( &headerStream, headerBuffer, 64 );
writePacketHeader( &headerStream, PGP_PACKET_DATA,
PGP_DATA_HEADER_SIZE + envelopeInfoPtr->payloadSize );
swrite( &headerStream, "b\x00\x00\x00\x00\x00",
PGP_DATA_HEADER_SIZE );
status = envelopeInfoPtr->copyToEnvelope( envelopeInfoPtr,
headerBuffer, ( int ) stell( &headerStream ) );
sMemClose( &headerStream );
/* We've processed the header, if this is signed data we start
hashing from this point (the PGP RFCs are wrong in this
regard, only the payload is hashed, not the entire packet) */
if( envelopeInfoPtr->usage == ACTION_SIGN )
envelopeInfoPtr->hashActionsActive = TRUE;
/* We're finished */
state = PGP_ENVSTATE_DONE;
}
}
/* Remember the state information */
envelopeInfoPtr->pgpEnvState = state;
return( status );
}
/* Output as much of the postamble as possible into the envelope buffer */
static int emitPostamble( ENVELOPE_INFO *envelopeInfoPtr )
{
STREAM *stream = &envelopeInfoPtr->auxStream;
RESOURCE_DATA msgData;
BYTE extraData[ 1024 ], *extraDataPtr = extraData;
BYTE hash[ CRYPT_MAX_HASHSIZE ], signature[ CRYPT_MAX_PKCSIZE ];
int extraDataLength = 1024, signatureLength, iAndSlength = 0, status;
/* If there's any data left in the auxiliary buffer, try and empty that
first */
if( envelopeInfoPtr->auxBufPos && copyFromAuxBuffer( envelopeInfoPtr ) )
return( CRYPT_ERROR_OVERFLOW );
/* The only PGP packet which 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 )
{
/* Flush any remaining data from internal buffers into the envelope
buffer if necessary */
if( envelopeInfoPtr->envState == ENVSTATE_NONE )
{
status = envelopeInfoPtr->copyToEnvelope( envelopeInfoPtr,
( BYTE * ) "", 0 );
if( cryptStatusError( status ) )
return( status );
}
/* We're done */
envelopeInfoPtr->envState = ENVSTATE_DONE;
return( CRYPT_OK );
}
/* If we didn't get through flushing the signature data into the main
buffer the last time, we've done it now and can wrap up */
if( envelopeInfoPtr->envState == ENVSTATE_SIGNATURE )
{
envelopeInfoPtr->envState = ENVSTATE_DONE;
return( CRYPT_OK );
}
/* Check whether there's an issuerAndSerialNumber present and allocate a
larger buffer for it if necessary. If it's too big for the auxiliary
buffer (which would make it a highly peculiar cert) we don't include
this info, since it's usually never used (the PKCS #7/CMS/SMIME
enveloping code dynamically expands the buffer, but it's of low
enough importance in PGP that it's not really worth the extra
complexity) */
setResourceData( &msgData, NULL, 0 );
status = krnlSendMessage( envelopeInfoPtr->postActionList->iCryptHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
if( cryptStatusOK( status ) && \
msgData.length < envelopeInfoPtr->auxBufSize - 128 )
{
if( msgData.length > extraDataLength - 128 )
{
extraDataLength = 128 + msgData.length;
if( ( extraDataPtr = malloc( extraDataLength ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
}
iAndSlength = msgData.length;
}
/* Complete the hashing and create the signature. In theory this could
get ugly because there could be multiple one-pass signature packets
present, however PGP handles multiple signatures by nesting them so
this isn't a problem.
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
we can create now, hash the portion which is hashed (all but the last
16 bits, the length of the unathenticated attributes), and then go
back and assemble the whole thing including the length and signature
later on from the individual parts */
status = extraDataLength = \
writeSignaturePacketHeader( extraData, extraDataLength,
envelopeInfoPtr->postActionList->iCryptHandle,
envelopeInfoPtr->actionList->iCryptHandle,
iAndSlength );
status = krnlSendMessage( envelopeInfoPtr->actionList->iCryptHandle,
RESOURCE_IMESSAGE_CTX_HASH,
extraData, extraDataLength - 2 );
if( cryptStatusOK( status ) )
{
BYTE buffer[ 8 ], *bufPtr = buffer + 2;
/* Hash in even more stuff at the end */
buffer[ 0 ] = 0x04;
buffer[ 1 ] = 0xFF;
mputBLong( bufPtr, extraDataLength - 2 );
status = krnlSendMessage( envelopeInfoPtr->actionList->iCryptHandle,
RESOURCE_IMESSAGE_CTX_HASH, buffer, 6 );
}
if( cryptStatusOK( status ) )
status = krnlSendMessage( envelopeInfoPtr->actionList->iCryptHandle,
RESOURCE_IMESSAGE_CTX_HASH, "", 0 );
if( cryptStatusOK( status ) )
{
RESOURCE_DATA msgData;
setResourceData( &msgData, hash, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( envelopeInfoPtr->actionList->iCryptHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_HASHVALUE );
}
if( cryptStatusOK( status ) )
status = iCryptCreateSignatureEx( signature, &signatureLength,
CRYPT_FORMAT_PGP,
envelopeInfoPtr->postActionList->iCryptHandle,
envelopeInfoPtr->actionList->iCryptHandle,
CRYPT_UNUSED, CRYPT_UNUSED );
if( cryptStatusError( status ) )
{
zeroise( extraDataPtr, extraDataLength );
if( extraDataPtr != extraData )
free( extraDataPtr );
return( status );
}
/* Write the signature packet:
[ signature packet header ]
byte[2] hash check
mpi signature
Since we've already had to write half the packet earlier on in order
to hash it, we copy this pre-encoded information across and add the
header and trailer around it */
writePacketHeader( stream, PGP_PACKET_SIGNATURE,
extraDataLength + 2 + signatureLength );
swrite( stream, extraData, extraDataLength );
swrite( stream, hash, 2 ); /* Hash check */
status = swrite( stream, signature, signatureLength );
zeroise( extraDataPtr, extraDataLength );
zeroise( signature, CRYPT_MAX_PKCSIZE );
if( extraDataPtr != extraData )
free( extraDataPtr );
if( cryptStatusError( status ) )
return( status );
/* Flush the data through into the main buffer */
if( copyFromAuxStream( envelopeInfoPtr ) )
{
/* We couldn't flush it all through, remember that we're still in
the middle of the signature creation process */
envelopeInfoPtr->envState = ENVSTATE_SIGNATURE;
return( CRYPT_ERROR_OVERFLOW );
}
envelopeInfoPtr->envState = ENVSTATE_DONE;
return( status );
}
/****************************************************************************
* *
* Envelope Access Routines *
* *
****************************************************************************/
void initPGPEnveloping( ENVELOPE_INFO *envelopeInfoPtr )
{
/* Set the access method pointers */
envelopeInfoPtr->emitPreamble = emitPreamble;
envelopeInfoPtr->emitPostamble = emitPostamble;
envelopeInfoPtr->checkCryptAlgo = checkCryptAlgo;
envelopeInfoPtr->checkHashAlgo = checkHashAlgo;
/* Set up the processing state information */
envelopeInfoPtr->pgpEnvState = PGP_ENVSTATE_NONE;
/* Set the PGP default algorithms. PGP is a bit tricky since there's no
simple function we can use to check whether a particular algorithm is
compatible with the underlying data format, so we have to hardcode in
the allowed values here */
krnlSendMessage( envelopeInfoPtr->ownerHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&envelopeInfoPtr->defaultHash, CRYPT_OPTION_ENCR_HASH );
if( !isPGPHashAlgo( envelopeInfoPtr->defaultHash ) )
envelopeInfoPtr->defaultHash = CRYPT_ALGO_SHA;
krnlSendMessage( envelopeInfoPtr->ownerHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&envelopeInfoPtr->defaultAlgo, CRYPT_OPTION_ENCR_ALGO );
if( isPGPCryptAlgo( envelopeInfoPtr->defaultAlgo ) )
envelopeInfoPtr->defaultAlgo = CRYPT_ALGO_3DES;
envelopeInfoPtr->defaultMAC = CRYPT_ERROR;
/* Turn off segmentation of the envelope payload (PGP has a single
length at the start of the data) */
envelopeInfoPtr->flags |= ENVELOPE_NOSEGMENT;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -