📄 pgp_rd.c
字号:
retExt( status,
( status, errorInfo,
"Invalid PGP userID information for key packet group %d",
keyGroupNo ) );
}
/* If there's no user ID present, set a generic label */
if( pgpInfo->lastUserID <= 0 )
{
pgpInfo->userID[ 0 ] = "PGP key (no user ID found)";
pgpInfo->userIDlen[ 0 ] = 26;
pgpInfo->lastUserID = 1;
}
return( CRYPT_OK );
}
/* Process the information in the packet group */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 6 ) ) \
static int processPacketGroup( INOUT STREAM *stream,
INOUT PGP_INFO *pgpInfo,
IN_OPT const KEY_MATCH_INFO *keyMatchInfo,
INOUT_OPT PGP_KEYINFO **matchedKeyInfoPtrPtr,
IN_INT_SHORT_Z const int keyGroupNo,
INOUT ERROR_INFO *errorInfo )
{
int iterationCount, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( pgpInfo, sizeof( PGP_INFO ) ) );
assert( ( keyMatchInfo == NULL && matchedKeyInfoPtrPtr == NULL ) || \
( isReadPtr( keyMatchInfo, sizeof( KEY_MATCH_INFO ) ) && \
isWritePtr( matchedKeyInfoPtrPtr, sizeof( PGP_KEYINFO * ) ) ) );
REQUIRES( ( keyMatchInfo == NULL && matchedKeyInfoPtrPtr == NULL ) || \
( keyMatchInfo != NULL && matchedKeyInfoPtrPtr != NULL && \
pgpInfo->keyData != NULL && \
pgpInfo->keyDataLen == KEYRING_BUFSIZE ) );
REQUIRES( keyGroupNo >= 0 && keyGroupNo < MAX_INTLENGTH_SHORT );
REQUIRES( errorInfo != NULL );
/* Clear the index information before we read the current key(s), since
it may already have been initialised during a previous (incomplete)
key read */
memset( &pgpInfo->key, 0, sizeof( PGP_KEYINFO ) );
memset( &pgpInfo->subKey, 0, sizeof( PGP_KEYINFO ) );
memset( pgpInfo->userID, 0, sizeof( char * ) * MAX_PGP_USERIDS );
memset( pgpInfo->userIDlen, 0, sizeof( int ) * MAX_PGP_USERIDS );
pgpInfo->lastUserID = 0;
/* Read all the packets in this packet group */
for( status = CRYPT_OK, iterationCount = 0;
cryptStatusOK( status ) && sMemDataLeft( stream ) > 0 && \
iterationCount++ < FAILSAFE_ITERATIONS_MED;
iterationCount++ )
{
status = readKey( stream, pgpInfo, keyGroupNo, errorInfo );
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
if( cryptStatusError( status ) )
{
if( status != OK_SPECIAL && status != CRYPT_ERROR_NOSECURE )
return( status );
/* There's either something in the key information that we can't
handle or it's stored with no security, skip the key */
if( keyMatchInfo == NULL )
pgpFreeEntry( pgpInfo );
return( status );
}
/* If we're reading all keys, we're done */
if( keyMatchInfo == NULL )
return( CRYPT_OK );
/* We're searching for a particular key, see if this is the one */
if( pgpCheckKeyMatch( pgpInfo, &pgpInfo->key, keyMatchInfo ) )
{
*matchedKeyInfoPtrPtr = &pgpInfo->key;
return( CRYPT_OK );
}
if( pgpCheckKeyMatch( pgpInfo, &pgpInfo->subKey, keyMatchInfo ) )
{
*matchedKeyInfoPtrPtr = &pgpInfo->subKey;
return( CRYPT_OK );
}
/* No match, tell the caller to keep looking */
return( CRYPT_ERROR_NOTFOUND );
}
/****************************************************************************
* *
* Read a Keyring *
* *
****************************************************************************/
/* Read an entire keyring. This function can be used in one of two ways, if
key match information is supplied each packet will be checked against it
and the read will exit when a match is found (used for public keyrings).
If no key match information is supplied, all keys will be read into
memory (used for private keyrings) */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4, 8, 9 ) ) \
static int processKeyringPackets( INOUT STREAM *stream,
IN_ARRAY( maxNoPgpObjects ) PGP_INFO *pgpInfo,
IN_LENGTH_SHORT const int maxNoPgpObjects,
OUT_BUFFER_FIXED( bufSize ) BYTE *buffer,
IN_LENGTH_SHORT_MIN( 64 ) const int bufSize,
IN_OPT const KEY_MATCH_INFO *keyMatchInfo,
INOUT_OPT PGP_KEYINFO **matchedKeyInfoPtrPtr,
OUT BOOLEAN *unhandledDataPresent,
INOUT ERROR_INFO *errorInfo )
{
BYTE streamBuffer[ STREAM_BUFSIZE + 8 ];
BOOLEAN moreData, insecureKeys = FALSE;
int bufEnd, keyGroupNo = 0, iterationCount, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( pgpInfo, sizeof( PGP_INFO ) * maxNoPgpObjects ) );
assert( isWritePtr( buffer, bufSize ) );
assert( ( keyMatchInfo == NULL && matchedKeyInfoPtrPtr == NULL ) || \
( isReadPtr( keyMatchInfo, sizeof( KEY_MATCH_INFO ) ) && \
isWritePtr( matchedKeyInfoPtrPtr, sizeof( PGP_KEYINFO * ) ) ) );
assert( isWritePtr( unhandledDataPresent, sizeof( BOOLEAN ) ) );
REQUIRES( maxNoPgpObjects >= 1 && maxNoPgpObjects < MAX_INTLENGTH_SHORT );
REQUIRES( bufSize > 64 && bufSize < MAX_INTLENGTH_SHORT );
REQUIRES( ( keyMatchInfo == NULL && matchedKeyInfoPtrPtr == NULL ) || \
( keyMatchInfo != NULL && matchedKeyInfoPtrPtr != NULL && \
pgpInfo->keyData != NULL && \
pgpInfo->keyDataLen == KEYRING_BUFSIZE ) );
REQUIRES( errorInfo != NULL );
/* Clear return value */
*unhandledDataPresent = FALSE;
/* Scan all the objects in the file. This is implemented as a sliding
window that reads a certain amount of data into a lookahead buffer
and then tries to identify a packet group in the buffer. If we need
to skip packets (for example due to unknown algorithms) we mark the
keyset as read-only since it's no longer safe for us to write the
incompletely-processed data to disk */
sioctl( stream, STREAM_IOCTL_IOBUFFER, streamBuffer, STREAM_BUFSIZE );
for( moreData = TRUE, bufEnd = 0, iterationCount = 0;
( moreData || bufEnd > 0 ) && \
iterationCount < FAILSAFE_ITERATIONS_MAX;
iterationCount++ )
{
PGP_INFO *pgpInfoPtr = &pgpInfo[ keyGroupNo ];
STREAM keyStream;
int length = DUMMY_INIT; /* Init needed by gcc */
/* Fill the lookahead buffer:
buffer bufEnd bufSize
| | |
v v v
+-----------+---------------+
|///////////| |
+-----------+---------------+
|
+-- length --> */
if( moreData )
{
REQUIRES( bufEnd >= 0 && bufEnd < bufSize );
status = length = sread( stream, buffer + bufEnd,
bufSize - bufEnd );
if( status <= 0 )
{
/* If we read nothing and there's nothing left in the buffer,
we're done */
if( bufEnd <= 0 )
{
/* If we've previously read at least one group of key
packets, we're OK */
if( keyGroupNo > 0 )
status = CRYPT_OK;
return( status );
}
/* There's still data in the buffer, we can continue until
we drain it */
length = 0;
}
if( length < bufSize - bufEnd )
{
/* We didn't get as much as we requested, there's nothing
left to read */
moreData = FALSE;
}
bufEnd += length;
}
/* Determine the size of the group of key packets in the buffer */
status = scanPacketGroup( buffer, bufEnd, &length );
if( status == OK_SPECIAL )
{
/* Remember that we hit something that we couldn't process */
*unhandledDataPresent = TRUE;
/* If the packet group is contained within the buffer, remove
the problem packets and continue */
if( length <= bufEnd )
{
if( bufEnd - length > 0 )
memmove( buffer, buffer + length, bufEnd - length );
bufEnd -= length;
continue;
}
ENSURES( length > bufEnd );
/* The packet group overflows the buffer, skip the remaining
contents and continue */
status = sseek( stream, stell( stream ) + ( length - bufEnd ) );
if( cryptStatusError( status ) )
break;
bufEnd = 0;
continue;
}
if( cryptStatusError( status ) )
{
retExt( status,
( status, errorInfo,
"Couldn't parse key packet group %d", keyGroupNo ) );
}
if( length <= 0 )
return( CRYPT_OK );
/* Move the packet group from the keyring buffer to the key data */
if( keyMatchInfo == NULL )
{
/* It's a read of all packets, allocate room for the current
packet group */
if( ( pgpInfoPtr->keyData = \
clAlloc( "readKeyring", length ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
pgpInfoPtr->keyDataLen = length;
}
memcpy( pgpInfoPtr->keyData, buffer, length );
if( bufEnd > length )
memmove( buffer, buffer + length, bufEnd - length );
bufEnd -= length;
/* Process the current packet group */
sMemConnect( &keyStream, pgpInfoPtr->keyData, length );
status = processPacketGroup( &keyStream, pgpInfoPtr, keyMatchInfo,
matchedKeyInfoPtrPtr, keyGroupNo,
errorInfo );
sMemDisconnect( &keyStream );
if( cryptStatusError( status ) )
{
/* If we were looking for a match for a particular key and
didn't find it, continue */
if( keyMatchInfo != NULL && status == CRYPT_ERROR_NOTFOUND )
continue;
/* If it's not a recoverable error, exit */
if( status != OK_SPECIAL && status != CRYPT_ERROR_NOSECURE )
return( status );
/* Remember that we hit something that we couldn't process, and
optionally an (unusable) unprotected key */
*unhandledDataPresent = TRUE;
if( status == CRYPT_ERROR_NOSECURE )
insecureKeys = TRUE;
continue;
}
/* If we're looking for a particular key, we've found it */
if( keyMatchInfo != NULL )
return( CRYPT_OK );
/* We're reading all keys, move on to the next empty slot. Note
that we only get to this point if we've been able to do something
with the key, if not then the unhandledDataPresent flag is set
without moving on to the next key group */
keyGroupNo++;
if( keyGroupNo >= maxNoPgpObjects )
{
retExt( CRYPT_ERROR_OVERFLOW,
( CRYPT_ERROR_OVERFLOW, errorInfo,
"Maximum keyset object item count %d reached, no more "
"room to add further items", maxNoPgpObjects ) );
}
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MAX );
/* If we were looking for a specific match, we haven't found it */
if( keyMatchInfo != NULL )
return( CRYPT_ERROR_NOTFOUND );
/* If we haven't found any keys that we can use let the caller know.
The error code to return here is a bit complex because we can skip
keys either because there's something in the key data that we can't
process or because the keys aren't sufficiently protected for us to
trust them. The most complex case is when both situations occur.
To keep it simple, if there are any insecure keys then we report
CRYPT_ERROR_NOSECURE on the basis that if the keys had been
appropriately secured then we might have been able to process them
and return one */
if( keyGroupNo <= 0 )
{
return( insecureKeys ? CRYPT_ERROR_NOSECURE : \
CRYPT_ERROR_NOTFOUND );
}
return( CRYPT_OK );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 6 ) ) \
int pgpReadKeyring( INOUT STREAM *stream,
IN_ARRAY( maxNoPgpObjects ) PGP_INFO *pgpInfo,
IN_LENGTH_SHORT const int maxNoPgpObjects,
IN_OPT const KEY_MATCH_INFO *keyMatchInfo,
INOUT_OPT PGP_KEYINFO **matchedKeyInfoPtrPtr,
INOUT ERROR_INFO *errorInfo )
{
BOOLEAN unhandledDataPresent;
BYTE *buffer;
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( pgpInfo, sizeof( PGP_INFO ) * maxNoPgpObjects ) );
assert( ( keyMatchInfo == NULL && matchedKeyInfoPtrPtr == NULL ) || \
( isReadPtr( keyMatchInfo, sizeof( KEY_MATCH_INFO ) ) && \
isWritePtr( matchedKeyInfoPtrPtr, sizeof( PGP_KEYINFO * ) ) ) );
REQUIRES( maxNoPgpObjects >= 1 && maxNoPgpObjects < MAX_INTLENGTH_SHORT );
REQUIRES( ( keyMatchInfo == NULL && matchedKeyInfoPtrPtr == NULL ) || \
( keyMatchInfo != NULL && matchedKeyInfoPtrPtr != NULL && \
pgpInfo->keyData != NULL && \
pgpInfo->keyDataLen == KEYRING_BUFSIZE ) );
REQUIRES( errorInfo != NULL );
/* Clear the return value */
if( matchedKeyInfoPtrPtr != NULL )
*matchedKeyInfoPtrPtr = NULL;
/* Since PGP keyrings just contain an arbitrary collection of packets
concatenated together we can't tell in advance how much data we
should be reading. Because of this we have to set the file stream to
allow partial reads without returning a read error */
if( ( buffer = clAlloc( "readKeyring", KEYRING_BUFSIZE ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
sioctl( stream, STREAM_IOCTL_PARTIALREAD, NULL, TRUE );
status = processKeyringPackets( stream, pgpInfo, maxNoPgpObjects,
buffer, KEYRING_BUFSIZE,
keyMatchInfo, matchedKeyInfoPtrPtr,
&unhandledDataPresent, errorInfo );
sioctl( stream, STREAM_IOCTL_IOBUFFER, NULL, 0 );
clFree( "readKeyring", buffer );
if( cryptStatusError( status ) )
return( status );
/* If we couldn't process one or more packets let the caller know that
not all keyring data is present in memory */
return( unhandledDataPresent ? OK_SPECIAL : CRYPT_OK );
}
#endif /* USE_PGPKEYS */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -