cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
pgp.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib PGP Keyset Routines *
4 * Copyright Peter Gutmann 1992-2007 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "misc_rw.h"
11  #include "keyset.h"
12  #include "pgp_key.h"
13  #include "pgp.h"
14 #else
15  #include "crypt.h"
16  #include "enc_dec/misc_rw.h"
17  #include "keyset/keyset.h"
18  #include "keyset/pgp_key.h"
19  #include "misc/pgp.h"
20 #endif /* Compiler-specific includes */
21 
22 #ifdef USE_PGPKEYS
23 
24 /* A PGP private keyset can contain multiple key objects so before we do
25  anything with the keyset we scan it and build an in-memory index of
26  what's present. When we perform an update we just flush the in-memory
27  information to disk.
28 
29  Each keyset can contain information for multiple personalities (although
30  for private keys it's unlikely to contain more than a small number), we
31  allow a maximum of MAX_PGP_OBJECTS per keyset. A setting of 16 objects
32  consumes ~4K of memory (16 x ~256) so we choose that as the limit */
33 
34 #ifdef CONFIG_CONSERVE_MEMORY
35  #define MAX_PGP_OBJECTS 4
36 #else
37  #define MAX_PGP_OBJECTS 16
38 #endif /* CONFIG_CONSERVE_MEMORY */
39 
40 /****************************************************************************
41 * *
42 * Utility Routines *
43 * *
44 ****************************************************************************/
45 
46 /* Find a free PGP keyset entry */
47 
49 static PGP_INFO *findFreeEntry( IN_ARRAY( noPgpObjects ) \
50  const PGP_INFO *pgpInfo,
51  IN_LENGTH_SHORT const int noPgpObjects )
52  {
53  int i;
54 
55  assert( isReadPtr( pgpInfo, \
56  sizeof( PGP_INFO ) * noPgpObjects ) );
57 
58  REQUIRES_N( noPgpObjects >= 1 && noPgpObjects < MAX_INTLENGTH_SHORT );
59 
60  for( i = 0; i < noPgpObjects && i < FAILSAFE_ITERATIONS_MED; i++ )
61  {
62  if( pgpInfo[ i ].keyData == NULL )
63  break;
64  }
65  ENSURES_N( i < FAILSAFE_ITERATIONS_MED );
66  if( i >= noPgpObjects )
67  return( NULL );
68 
69  return( ( PGP_INFO * ) &pgpInfo[ i ] );
70  }
71 
72 /* Free object entries */
73 
74 STDC_NONNULL_ARG( ( 1 ) ) \
75 void pgpFreeEntry( INOUT PGP_INFO *pgpInfo )
76  {
77  assert( isWritePtr( pgpInfo, sizeof( PGP_INFO ) ) );
78 
79  if( pgpInfo->keyData != NULL )
80  {
81  zeroise( pgpInfo->keyData, pgpInfo->keyDataLen );
82  clFree( "pgpFreeEntry", pgpInfo->keyData );
83  pgpInfo->keyData = NULL;
84  pgpInfo->keyDataLen = 0;
85  }
86  zeroise( pgpInfo, sizeof( PGP_INFO ) );
87  }
88 
89 /* Create a decryption context for the private key from a user-supplied
90  password */
91 
92 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
93 static int createDecryptionContext( OUT_HANDLE_OPT CRYPT_CONTEXT *iSessionKey,
94  const PGP_KEYINFO *keyInfo,
96  const void *password,
97  IN_LENGTH_NAME const int passwordLength )
98  {
99  CRYPT_CONTEXT iLocalContext;
100  MESSAGE_CREATEOBJECT_INFO createInfo;
102  static const int mode = CRYPT_MODE_CFB; /* int vs.enum */
103  int ivSize, status;
104 
105  assert( isWritePtr( iSessionKey, sizeof( CRYPT_CONTEXT ) ) );
106  assert( isReadPtr( keyInfo, sizeof( PGP_KEYINFO ) ) );
107  assert( isReadPtr( password, passwordLength ) );
108 
109  REQUIRES( passwordLength >= MIN_NAME_LENGTH && \
110  passwordLength < MAX_ATTRIBUTE_SIZE );
111 
112  /* Convert the user password into an encryption context */
113  setMessageCreateObjectInfo( &createInfo, keyInfo->cryptAlgo );
115  &createInfo, OBJECT_TYPE_CONTEXT );
116  if( cryptStatusError( status ) )
117  return( status );
118  iLocalContext = createInfo.cryptHandle;
119  status = krnlSendMessage( iLocalContext, IMESSAGE_SETATTRIBUTE,
120  ( MESSAGE_CAST ) &mode, CRYPT_CTXINFO_MODE );
121  if( cryptStatusOK( status ) )
122  {
123  status = pgpPasswordToKey( iLocalContext,
124  ( keyInfo->cryptAlgo == CRYPT_ALGO_AES && \
125  keyInfo->aesKeySize > 0 ) ? \
126  keyInfo->aesKeySize : CRYPT_UNUSED,
127  password, passwordLength,
128  keyInfo->hashAlgo,
129  ( keyInfo->saltSize > 0 ) ? \
130  keyInfo->salt : NULL, keyInfo->saltSize,
131  keyInfo->keySetupIterations );
132  }
133  if( cryptStatusError( status ) )
134  {
135  krnlSendNotifier( iLocalContext, IMESSAGE_DECREFCOUNT );
136  return( status );
137  }
138 
139  /* Load the IV into the context */
140  status = krnlSendMessage( iLocalContext, IMESSAGE_GETATTRIBUTE,
141  &ivSize, CRYPT_CTXINFO_IVSIZE );
142  if( cryptStatusOK( status ) && ivSize > keyInfo->ivSize )
143  status = CRYPT_ERROR_BADDATA;
144  if( cryptStatusOK( status ) )
145  {
146  setMessageData( &msgData, ( MESSAGE_CAST ) keyInfo->iv,
147  keyInfo->ivSize );
148  status = krnlSendMessage( iLocalContext, IMESSAGE_SETATTRIBUTE_S,
149  &msgData, CRYPT_CTXINFO_IV );
150  }
151  if( cryptStatusError( status ) )
152  {
153  krnlSendNotifier( iLocalContext, IMESSAGE_DECREFCOUNT );
154  return( status );
155  }
156  *iSessionKey = iLocalContext;
157 
158  return( CRYPT_OK );
159  }
160 
161 /****************************************************************************
162 * *
163 * Find a Key *
164 * *
165 ****************************************************************************/
166 
167 /* Generate a cryptlib-style key ID for a PGP key and check it against the
168  given key ID. This will really suck with large public keyrings since it
169  requires creating a context for each key that we check, but there's no
170  easy way around this and in any case it only occurs when using PGP keys
171  with non-PGP messages, which is fairly rare */
172 
174 static BOOLEAN matchKeyID( const PGP_KEYINFO *keyInfo,
175  IN_BUFFER( requiredIDlength ) const BYTE *requiredID,
176  IN_LENGTH_KEYID const int requiredIDlength,
177  const BOOLEAN isPGPkeyID )
178  {
179  CRYPT_CONTEXT iLocalContext;
180  MESSAGE_CREATEOBJECT_INFO createInfo;
182  BYTE keyID[ KEYID_SIZE + 8 ];
183  int status;
184 
185  assert( isReadPtr( keyInfo, sizeof( PGP_KEYINFO ) ) );
186  assert( isReadPtr( requiredID, requiredIDlength ) );
187 
188  ENSURES_B( requiredIDlength == PGP_KEYID_SIZE || \
189  requiredIDlength == KEYID_SIZE );
190 
191  /* If it's a PGP key ID we can check it directly against the two PGP
192  key IDs. We don't distinguish between the two ID types externally
193  because it's a pain for external code to have to know that there are
194  two ID types that look the same and are often used interchangeably
195  but of the two only the OpenPGP variant is valid for all keys (in
196  fact there are some broken PGP variants that use PGP 2.x IDs marked
197  as OpenPGP IDs, so checking both IDs is necessary for
198  interoperability). The mixing of ID types is safe because the
199  chances of a collision are miniscule and the worst that can happen is
200  that a signature check will fail (encryption keys are chosen by user
201  ID and not key ID so accidentally using the wrong key to encrypt
202  isn't an issue) */
203  if( isPGPkeyID )
204  {
205  ENSURES_B( requiredIDlength == PGP_KEYID_SIZE );
206 
207  if( !memcmp( requiredID, keyInfo->openPGPkeyID, PGP_KEYID_SIZE ) )
208  return( TRUE );
209  return( ( keyInfo->pkcAlgo == CRYPT_ALGO_RSA ) && \
210  !memcmp( requiredID, keyInfo->pgpKeyID, PGP_KEYID_SIZE ) );
211  }
212  ENSURES_B( requiredIDlength == KEYID_SIZE );
213 
214  /* Generate the key ID via a context. We have to set the OpenPGP key ID
215  before the key load to mark it as a PGP key otherwise the key check
216  will fail since it's not a full X9.42 key with DLP validation
217  parameters */
218  setMessageCreateObjectInfo( &createInfo, keyInfo->pkcAlgo );
220  &createInfo, OBJECT_TYPE_CONTEXT );
221  if( cryptStatusError( status ) )
222  {
223  DEBUG_DIAG(( "Couldn't create PKC context to generate key ID" ));
224  assert( DEBUG_WARN );
225  return( FALSE );
226  }
227  iLocalContext = createInfo.cryptHandle;
228  setMessageData( &msgData, ( MESSAGE_CAST ) keyInfo->openPGPkeyID,
229  PGP_KEYID_SIZE );
230  status = krnlSendMessage( iLocalContext, IMESSAGE_SETATTRIBUTE_S,
231  &msgData, CRYPT_IATTRIBUTE_KEYID_OPENPGP );
232  if( cryptStatusOK( status ) )
233  {
234  setMessageData( &msgData, keyInfo->pubKeyData,
235  keyInfo->pubKeyDataLen );
236  status = krnlSendMessage( iLocalContext, IMESSAGE_SETATTRIBUTE_S,
237  &msgData, CRYPT_IATTRIBUTE_KEY_PGP );
238  }
239  if( cryptStatusOK( status ) )
240  {
241  setMessageData( &msgData, keyID, KEYID_SIZE );
242  status = krnlSendMessage( iLocalContext, IMESSAGE_GETATTRIBUTE_S,
243  &msgData, CRYPT_IATTRIBUTE_KEYID );
244  }
245  krnlSendNotifier( iLocalContext, IMESSAGE_DECREFCOUNT );
246  if( cryptStatusError( status ) )
247  {
248  DEBUG_DIAG(( "Couldn't initialise PKC context to generate key ID" ));
249  assert( DEBUG_WARN );
250  return( FALSE );
251  }
252 
253  /* Check if it's the same as the key ID that we're looking for */
254  return( !memcmp( requiredID, keyID, requiredIDlength ) ? TRUE : FALSE );
255  }
256 
257 /* Check whether a key matches the required user ID */
258 
259 CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
260 BOOLEAN pgpCheckKeyMatch( const PGP_INFO *pgpInfo,
261  const PGP_KEYINFO *keyInfo,
263  {
264  int i;
265 
266  assert( isReadPtr( pgpInfo, sizeof( PGP_INFO ) ) );
267  assert( isReadPtr( keyInfo, sizeof( PGP_KEYINFO ) ) );
268  assert( isReadPtr( keyMatchInfo, sizeof( KEY_MATCH_INFO ) ) );
269 
270  /* If there's an explicitly requested key usage type, make sure that the
271  key is suitable */
272  if( ( keyMatchInfo->flags & KEYMGMT_MASK_USAGEOPTIONS ) && \
273  !( keyInfo->usageFlags & keyMatchInfo->flags ) )
274  return( FALSE );
275 
276  /* If we're searching by key ID, check whether this is the packet that
277  we want */
278  if( keyMatchInfo->keyIDtype == CRYPT_IKEYID_KEYID || \
279  keyMatchInfo->keyIDtype == CRYPT_IKEYID_PGPKEYID )
280  {
281  return( matchKeyID( keyInfo, keyMatchInfo->keyID,
282  keyMatchInfo->keyIDlength,
283  ( keyMatchInfo->keyIDtype == CRYPT_IKEYID_PGPKEYID ) ? \
284  TRUE : FALSE ) );
285  }
286 
287  REQUIRES_B( keyMatchInfo->keyIDtype == CRYPT_KEYID_NAME || \
288  keyMatchInfo->keyIDtype == CRYPT_KEYID_URI );
289 
290  /* We're searching by user ID, walk down the list of userIDs checking
291  for a match */
292  for( i = 0; i < pgpInfo->lastUserID && i < MAX_PGP_USERIDS; i++ )
293  {
294  /* Check if it's the one that we want. If it's a key with subkeys
295  and no usage type is explicitly specified this will always return
296  the main key. This is the best solution since the main key is
297  always a signing key, which is more likely to be what the user
298  wants. Encryption keys will typically only be accessed via
299  envelopes and the enveloping code can specify a preference of an
300  encryption-capable key, while signing keys will be read directly
301  and pushed into the envelope */
302  if( strFindStr( pgpInfo->userID[ i ], pgpInfo->userIDlen[ i ],
303  ( char * ) keyMatchInfo->keyID,
304  keyMatchInfo->keyIDlength ) >= 0 )
305  return( TRUE );
306  }
307  ENSURES_B( i < MAX_PGP_USERIDS );
308 
309  return( FALSE );
310  }
311 
312 /* Locate a key based on an ID. This is complicated somewhat by the fact
313  that PGP groups multiple keys around the same textual ID so we have to
314  check both keys and subkeys for a possible match */
315 
317 static PGP_INFO *findEntry( const PGP_INFO *pgpInfo,
318  IN_LENGTH_SHORT const int noPgpObjects,
320  IN_BUFFER( keyIDlength ) const void *keyID,
321  IN_LENGTH_KEYID const int keyIDlength,
322  IN_FLAGS_Z( KEYMGMT ) const int requestedUsage,
323  OUT_OPT_PTR_OPT PGP_KEYINFO **keyInfo )
324  {
325  CONST_INIT_STRUCT_4( KEY_MATCH_INFO keyMatchInfo, \
326  keyIDtype, keyID, keyIDlength, requestedUsage );
327  int i;
328 
329  CONST_SET_STRUCT( keyMatchInfo.keyIDtype = keyIDtype; \
330  keyMatchInfo.keyID = keyID; \
331  keyMatchInfo.keyIDlength = keyIDlength; \
332  keyMatchInfo.flags = requestedUsage );
333 
334  assert( isReadPtr( pgpInfo, sizeof( PGP_INFO ) ) );
335  assert( isReadPtr( keyID, keyIDlength ) );
336  assert( keyInfo == NULL || \
337  isWritePtr( keyInfo, sizeof( PGP_KEYINFO * ) ) );
338 
339  REQUIRES_N( noPgpObjects >= 1 && noPgpObjects < MAX_INTLENGTH_SHORT );
340  REQUIRES_N( keyIDtype == CRYPT_KEYID_NAME || \
341  keyIDtype == CRYPT_KEYID_URI || \
342  keyIDtype == CRYPT_IKEYID_KEYID || \
343  keyIDtype == CRYPT_IKEYID_PGPKEYID );
344  REQUIRES_N( keyIDlength >= MIN_NAME_LENGTH && \
345  keyIDlength < MAX_ATTRIBUTE_SIZE );
346  REQUIRES_N( requestedUsage >= KEYMGMT_FLAG_NONE && \
347  requestedUsage < KEYMGMT_FLAG_MAX );
348  REQUIRES_N( ( requestedUsage & KEYMGMT_MASK_USAGEOPTIONS ) != \
349  KEYMGMT_MASK_USAGEOPTIONS );
350 
351  /* Clear return value */
352  if( keyInfo != NULL )
353  *keyInfo = NULL;
354 
355  for( i = 0; i < noPgpObjects && i < FAILSAFE_ITERATIONS_MED; i++ )
356  {
357  if( pgpCheckKeyMatch( &pgpInfo[ i ], &pgpInfo[ i ].key,
358  &keyMatchInfo ) )
359  {
360  if( keyInfo != NULL )
361  *keyInfo = ( PGP_KEYINFO * ) &pgpInfo[ i ].key;
362  return( ( PGP_INFO * ) &pgpInfo[ i ] );
363  }
364  if( pgpCheckKeyMatch( &pgpInfo[ i ], &pgpInfo[ i ].subKey,
365  &keyMatchInfo ) )
366  {
367  if( keyInfo != NULL )
368  *keyInfo = ( PGP_KEYINFO * ) &pgpInfo[ i ].subKey;
369  return( ( PGP_INFO * ) &pgpInfo[ i ] );
370  }
371  }
372  ENSURES_N( i < FAILSAFE_ITERATIONS_MED );
373 
374  return( NULL );
375  }
376 
377 /****************************************************************************
378 * *
379 * Get a Key *
380 * *
381 ****************************************************************************/
382 
383 /* Read key data from a PGP keyring */
384 
385 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 5 ) ) \
386 static int getItemFunction( INOUT KEYSET_INFO *keysetInfoPtr,
388  IN_ENUM( KEYMGMT_ITEM ) \
389  const KEYMGMT_ITEM_TYPE itemType,
390  IN_KEYID const CRYPT_KEYID_TYPE keyIDtype,
391  IN_BUFFER( keyIDlength ) const void *keyID,
392  IN_LENGTH_KEYID const int keyIDlength,
393  IN_OPT void *auxInfo,
395  IN_FLAGS_Z( KEYMGMT ) const int flags )
396  {
397  CRYPT_CONTEXT iDecryptionKey = DUMMY_INIT, iLocalContext;
398  PGP_INFO *pgpInfo = ( PGP_INFO * ) keysetInfoPtr->keyData;
399  PGP_KEYINFO *keyInfo;
400  MESSAGE_CREATEOBJECT_INFO createInfo;
402  MESSAGE_DATA msgData;
403  const int auxInfoMaxLength = *auxInfoLength;
404  int status;
405 
406  assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
407  assert( isWritePtr( iCryptHandle, sizeof( CRYPT_HANDLE ) ) );
408  assert( isReadPtr( keyID, keyIDlength ) );
409  assert( ( auxInfo == NULL && auxInfoMaxLength == 0 ) || \
410  isReadPtr( auxInfo, auxInfoMaxLength ) );
411 
412  REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
413  ( keysetInfoPtr->subType == KEYSET_SUBTYPE_PGP_PUBLIC ||
414  keysetInfoPtr->subType == KEYSET_SUBTYPE_PGP_PRIVATE ) );
415  REQUIRES( itemType == KEYMGMT_ITEM_PUBLICKEY || \
416  itemType == KEYMGMT_ITEM_PRIVATEKEY );
417  REQUIRES( keyIDtype == CRYPT_KEYID_NAME || \
418  keyIDtype == CRYPT_KEYID_URI || \
419  keyIDtype == CRYPT_IKEYID_KEYID || \
420  keyIDtype == CRYPT_IKEYID_PGPKEYID );
421  REQUIRES( keyIDlength >= MIN_NAME_LENGTH && \
422  keyIDlength < MAX_ATTRIBUTE_SIZE );
423  REQUIRES( ( auxInfo == NULL && *auxInfoLength == 0 ) || \
424  ( auxInfo != NULL && \
425  *auxInfoLength > 0 && \
426  *auxInfoLength < MAX_INTLENGTH_SHORT ) );
427  REQUIRES( flags >= KEYMGMT_FLAG_NONE && flags < KEYMGMT_FLAG_MAX );
428 
429  /* Find the requested item. This is complicated somewhat by the fact
430  that private keys are held in memory while public keys (which can
431  be arbitrarily numerous) are held on disk. This means that the former
432  (and also public keys read from a private-key keyring) are found with
433  a quick in-memory search while the latter require a scan of the
434  keyring on disk */
435  if( itemType == KEYMGMT_ITEM_PRIVATEKEY || \
436  keysetInfoPtr->subType == KEYSET_SUBTYPE_PGP_PRIVATE )
437  {
438  /* Try and locate the appropriate object in the PGP collection */
439  pgpInfo = findEntry( keysetInfoPtr->keyData, MAX_PGP_OBJECTS,
440  keyIDtype, keyID, keyIDlength, flags,
441  &keyInfo );
442  if( pgpInfo == NULL )
443  return( CRYPT_ERROR_NOTFOUND );
444  }
445  else
446  {
447  CONST_INIT_STRUCT_4( KEY_MATCH_INFO keyMatchInfo, \
448  keyIDtype, keyID, keyIDlength, flags );
449 
450  CONST_SET_STRUCT( keyMatchInfo.keyIDtype = keyIDtype; \
451  keyMatchInfo.keyID = keyID; \
452  keyMatchInfo.keyIDlength = keyIDlength; \
453  keyMatchInfo.flags = flags );
454 
455  /* Try and find the required key in the keyset */
456  sseek( &keysetInfoPtr->keysetFile->stream, 0 );
457  status = pgpReadKeyring( &keysetInfoPtr->keysetFile->stream,
458  pgpInfo, 1, &keyMatchInfo, &keyInfo,
459  KEYSET_ERRINFO );
460  if( cryptStatusError( status ) && status != OK_SPECIAL )
461  return( status );
462  }
463 
464  /* If it's just a check or label read, we're done */
466  {
467  if( flags & KEYMGMT_FLAG_LABEL_ONLY )
468  {
469  const int userIDsize = min( pgpInfo->userIDlen[ 0 ],
470  auxInfoMaxLength );
471 
472  REQUIRES( pgpInfo->userIDlen[ 0 ] > 0 && \
473  pgpInfo->userIDlen[ 0 ] < MAX_INTLENGTH_SHORT );
474 
475  *auxInfoLength = userIDsize;
476  if( auxInfo != NULL )
477  memcpy( auxInfo, pgpInfo->userID[ 0 ], userIDsize );
478  }
479 
480  return( CRYPT_OK );
481  }
482 
483  /* Set up the key to decrypt the private-key fields if necessary */
484  if( itemType == KEYMGMT_ITEM_PRIVATEKEY )
485  {
486  /* If no password is supplied let the caller know that they need a
487  password */
488  if( auxInfo == NULL )
489  {
492  "Need a password to decrypt the private key" ) );
493  }
494 
495  /* If the key is stored as plaintext we can't do anything with it.
496  This is just a safety check, we never get here anyway, see the
497  comment in readSecretKeyDecryptionInfo() for details */
498  if( keyInfo->cryptAlgo == CRYPT_ALGO_NONE )
499  return( CRYPT_ERROR_WRONGKEY );
500 
501  /* Create a decryption context to decrypt the private key */
502  status = createDecryptionContext( &iDecryptionKey, keyInfo,
503  auxInfo, auxInfoMaxLength );
504  if( cryptStatusError( status ) )
505  {
506  retExt( status,
507  ( status, KEYSET_ERRINFO,
508  "Couldn't create decryption context for private key "
509  "from user password" ) );
510  }
511  }
512 
513  /* Load the key into the encryption context */
514  setMessageCreateObjectInfo( &createInfo, keyInfo->pkcAlgo );
516  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
518  if( cryptStatusError( status ) )
519  {
520  if( itemType == KEYMGMT_ITEM_PRIVATEKEY )
521  krnlSendNotifier( iDecryptionKey, IMESSAGE_DECREFCOUNT );
522  return( status );
523  }
524  iLocalContext = createInfo.cryptHandle;
525  if( itemType == KEYMGMT_ITEM_PRIVATEKEY )
526  {
527  REQUIRES( pgpInfo->userIDlen[ 0 ] > 0 && \
528  pgpInfo->userIDlen[ 0 ] < MAX_INTLENGTH_SHORT );
529 
530  setMessageData( &msgData, pgpInfo->userID[ 0 ],
531  min( pgpInfo->userIDlen[ 0 ],
532  CRYPT_MAX_TEXTSIZE ) );
533  status = krnlSendMessage( iLocalContext, IMESSAGE_SETATTRIBUTE_S,
534  &msgData, CRYPT_CTXINFO_LABEL );
535  }
536  if( cryptStatusOK( status ) )
537  {
538  setMessageData( &msgData, keyInfo->openPGPkeyID, PGP_KEYID_SIZE );
539  status = krnlSendMessage( iLocalContext, IMESSAGE_SETATTRIBUTE_S,
540  &msgData, CRYPT_IATTRIBUTE_KEYID_OPENPGP );
541  }
542  if( cryptStatusOK( status ) )
543  {
544  setMessageData( &msgData, keyInfo->pubKeyData,
545  keyInfo->pubKeyDataLen );
546  status = krnlSendMessage( iLocalContext, IMESSAGE_SETATTRIBUTE_S,
547  &msgData,
548  ( itemType == KEYMGMT_ITEM_PRIVATEKEY ) ? \
549  CRYPT_IATTRIBUTE_KEY_PGP_PARTIAL : \
550  CRYPT_IATTRIBUTE_KEY_PGP );
551  }
552  if( cryptStatusError( status ) )
553  {
554  krnlSendNotifier( iLocalContext, IMESSAGE_DECREFCOUNT );
555  retExt( status,
556  ( status, KEYSET_ERRINFO,
557  "Couldn't recreate key from stored %s key data",
558  ( itemType == KEYMGMT_ITEM_PRIVATEKEY ) ? \
559  "private" : "public" ) );
560  }
561 
562  /* If it's a public key, we're done */
563  if( itemType != KEYMGMT_ITEM_PRIVATEKEY )
564  {
565  *iCryptHandle = iLocalContext;
566 
567  return( CRYPT_OK );
568  }
569 
570  /* Import the encrypted key into the PKC context */
571  setMechanismWrapInfo( &mechanismInfo, keyInfo->privKeyData,
572  keyInfo->privKeyDataLen, NULL, 0, iLocalContext,
573  iDecryptionKey );
575  &mechanismInfo, pgpInfo->isOpenPGP ? \
576  ( keyInfo->hashedChecksum ?
581  krnlSendNotifier( iDecryptionKey, IMESSAGE_DECREFCOUNT );
582  if( cryptStatusError( status ) )
583  {
584  krnlSendNotifier( iLocalContext, IMESSAGE_DECREFCOUNT );
585  retExt( status,
586  ( status, KEYSET_ERRINFO,
587  "Couldn't unwrap private key" ) );
588  }
589  *iCryptHandle = iLocalContext;
590 
591  return( CRYPT_OK );
592  }
593 
594 /****************************************************************************
595 * *
596 * Add a Key *
597 * *
598 ****************************************************************************/
599 
600 /* Add an item to the PGP keyring */
601 
603 static int setItemFunction( INOUT KEYSET_INFO *keysetInfoPtr,
605  IN_ENUM( KEYMGMT_ITEM ) \
606  const KEYMGMT_ITEM_TYPE itemType,
607  IN_BUFFER_OPT( passwordLength ) const char *password,
608  IN_LENGTH_NAME_Z const int passwordLength,
609  IN_FLAGS( KEYMGMT ) const int flags )
610  {
611  PGP_INFO *pgpInfo = ( PGP_INFO * ) keysetInfoPtr->keyData, *pgpInfoPtr;
612  MESSAGE_DATA msgData;
613  BYTE iD[ CRYPT_MAX_HASHSIZE + 8 ];
615  char label[ CRYPT_MAX_TEXTSIZE + 1 + 8 ];
616  int algorithm, iDsize = DUMMY_INIT, status;
617 
618  assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
619  assert( ( itemType == KEYMGMT_ITEM_PUBLICKEY && \
620  password == NULL && passwordLength == 0 ) || \
621  ( itemType == KEYMGMT_ITEM_PRIVATEKEY && \
622  isReadPtr( password, passwordLength ) ) );
623 
624  REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
625  ( keysetInfoPtr->subType == KEYSET_SUBTYPE_PGP_PUBLIC ||
626  keysetInfoPtr->subType == KEYSET_SUBTYPE_PGP_PRIVATE ) );
627  REQUIRES( isHandleRangeValid( cryptHandle ) );
628  REQUIRES( itemType == KEYMGMT_ITEM_PUBLICKEY || \
629  itemType == KEYMGMT_ITEM_PRIVATEKEY );
630  REQUIRES( ( password == NULL && passwordLength == 0 ) || \
631  ( password != NULL && \
632  passwordLength >= MIN_NAME_LENGTH && \
633  passwordLength < MAX_ATTRIBUTE_SIZE ) );
634  REQUIRES( ( itemType == KEYMGMT_ITEM_PUBLICKEY && \
635  password == NULL && passwordLength == 0 ) || \
636  ( itemType == KEYMGMT_ITEM_PRIVATEKEY && \
637  password != NULL && passwordLength != 0 ) );
638  REQUIRES( flags == KEYMGMT_FLAG_NONE );
639 
640  /* Check the object and extract ID information from it */
641  status = krnlSendMessage( cryptHandle, IMESSAGE_CHECK, NULL,
643  if( cryptStatusOK( status ) )
644  {
645  status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE,
646  &algorithm, CRYPT_CTXINFO_ALGO );
647  if( cryptStatusOK( status ) && algorithm != CRYPT_ALGO_RSA )
648  {
649  /* For now we can only store RSA keys because of the peculiar
650  properties of PGP DLP keys, which are actually two keys
651  with entirely different semantics and attributes but are
652  nevertheless occasionally treated as a single key by PGP */
653  status = CRYPT_ARGERROR_NUM1;
654  }
655  }
656  if( cryptStatusOK( status ) )
657  {
658  setMessageData( &msgData, iD, CRYPT_MAX_HASHSIZE );
659  status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
660  &msgData, CRYPT_IATTRIBUTE_KEYID );
661  if( cryptStatusOK( status ) )
662  iDsize = msgData.length;
663  }
664  if( cryptStatusError( status ) )
665  {
666  return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
667  CRYPT_ARGERROR_NUM1 : status );
668  }
670  krnlSendMessage( cryptHandle, IMESSAGE_CHECK, NULL,
672 
673  /* If we're adding a private key make sure that there's a context and a
674  password present. Conversely if we're adding a public key make sure
675  that there's no password present. The password-check has already
676  been performed by the kernel but we perform a second check here just
677  to be safe. The private-key check can't be performed by the kernel
678  since it doesn't know the difference between public- and private-key
679  contexts */
680  switch( itemType )
681  {
683  if( password != NULL )
684  return( CRYPT_ARGERROR_STR1 );
685  break;
686 
688  if( !privkeyPresent )
689  {
692  "Item being added doesn't contain a private "
693  "key" ) );
694  }
695  if( password == NULL )
696  return( CRYPT_ARGERROR_STR1 );
697  break;
698 
699  default:
700  retIntError();
701  }
702 
703  /* Find out where we can add data and what needs to be added. At the
704  moment we only allow atomic adds since the semantics of PGP's dual
705  keys, with assorted optional attributes attached to one or both keys
706  can't easily be handled using a straightforward add */
707  pgpInfoPtr = findEntry( keysetInfoPtr->keyData, MAX_PGP_OBJECTS,
708  CRYPT_IKEYID_KEYID, iD, iDsize,
709  KEYMGMT_FLAG_NONE, NULL );
710  if( pgpInfoPtr != NULL )
711  {
714  "Item is already present in keyset" ) );
715  }
716 
717  /* Make sure that the label of what we're adding doesn't duplicate the
718  label of an existing object */
719  if( privkeyPresent )
720  {
721  setMessageData( &msgData, label, CRYPT_MAX_TEXTSIZE );
722  status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
723  &msgData, CRYPT_CTXINFO_LABEL );
724  if( cryptStatusError( status ) )
725  return( status );
726  if( findEntry( keysetInfoPtr->keyData, MAX_PGP_OBJECTS,
727  CRYPT_KEYID_NAME, msgData.data, msgData.length,
728  KEYMGMT_FLAG_NONE, NULL ) != NULL )
729  {
732  "Item with this label is already present" ) );
733  }
734  }
735 
736  /* Find out where we can add the new key data */
737  pgpInfoPtr = findFreeEntry( pgpInfo, MAX_PGP_OBJECTS );
738  if( pgpInfoPtr == NULL )
739  {
742  "No more room in keyset to add this item" ) );
743  }
744 
745  /* Not implemented yet */
746  return( CRYPT_ERROR_NOTAVAIL );
747  }
748 
749 /****************************************************************************
750 * *
751 * Init/Shutdown Functions *
752 * *
753 ****************************************************************************/
754 
755 /* Shutdown functions */
756 
757 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
758 static int shutdownFunction( INOUT KEYSET_INFO *keysetInfoPtr )
759  {
760  PGP_INFO *pgpInfo = ( PGP_INFO * ) keysetInfoPtr->keyData;
761 
762  assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
763 
764  REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
765  ( keysetInfoPtr->subType == KEYSET_SUBTYPE_PGP_PUBLIC ||
766  keysetInfoPtr->subType == KEYSET_SUBTYPE_PGP_PRIVATE ) );
767 
768  /* If there's no PGP information data cached, we're done */
769  if( pgpInfo == NULL )
770  return( CRYPT_OK );
771 
772  /* Free the cached key information */
773  if( keysetInfoPtr->subType == KEYSET_SUBTYPE_PGP_PRIVATE )
774  {
775  int i;
776 
777  for( i = 0; i < MAX_PGP_OBJECTS; i++ )
778  pgpFreeEntry( &pgpInfo[ i ] );
779  }
780  else
781  pgpFreeEntry( pgpInfo );
782  clFree( "shutdownFunction", pgpInfo );
783  keysetInfoPtr->keyData = NULL;
784  keysetInfoPtr->keyDataSize = 0;
785 
786  return( CRYPT_OK );
787  }
788 
789 /* PGP public keyrings can be arbitrarily large so we don't try to do any
790  preprocessing, all we do at this point is allocate the key information */
791 
793 static int initPublicFunction( INOUT KEYSET_INFO *keysetInfoPtr,
794  STDC_UNUSED const char *name,
795  STDC_UNUSED const int nameLength,
796  IN_ENUM( CRYPT_KEYOPT ) \
797  const CRYPT_KEYOPT_TYPE options )
798  {
799  PGP_INFO *pgpInfo;
800 
801  assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
802 
803  REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
804  keysetInfoPtr->subType == KEYSET_SUBTYPE_PGP_PUBLIC );
805  REQUIRES( name == NULL && nameLength == 0 );
806  REQUIRES( options >= CRYPT_KEYOPT_NONE && options < CRYPT_KEYOPT_LAST );
807 
808  /* Allocate memory for the key information */
809  if( ( pgpInfo = clAlloc( "initPublicFunction", \
810  sizeof( PGP_INFO ) ) ) == NULL )
811  return( CRYPT_ERROR_MEMORY );
812  memset( pgpInfo, 0, sizeof( PGP_INFO ) );
813  if( ( pgpInfo->keyData = clAlloc( "initPublicFunction", \
814  KEYRING_BUFSIZE ) ) == NULL )
815  {
816  clFree( "initPublicFunction", pgpInfo );
817  return( CRYPT_ERROR_MEMORY );
818  }
819  pgpInfo->keyDataLen = KEYRING_BUFSIZE;
820  keysetInfoPtr->keyData = pgpInfo;
821  keysetInfoPtr->keyDataSize = sizeof( PGP_INFO );
822 
823  return( CRYPT_OK );
824  }
825 
826 /* A PGP private keyring can contain multiple keys and whatnot so when we
827  open it we scan it and record various pieces of information about it that
828  we can use later when we need to access it */
829 
831 static int initPrivateFunction( INOUT KEYSET_INFO *keysetInfoPtr,
832  STDC_UNUSED const char *name,
833  STDC_UNUSED const int nameLength,
834  IN_ENUM( CRYPT_KEYOPT ) \
835  const CRYPT_KEYOPT_TYPE options )
836  {
837  PGP_INFO *pgpInfo;
838  int status;
839 
840  assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
841 
842  REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
843  keysetInfoPtr->subType == KEYSET_SUBTYPE_PGP_PRIVATE );
844  REQUIRES( name == NULL && nameLength == 0 );
845  REQUIRES( options >= CRYPT_KEYOPT_NONE && options < CRYPT_KEYOPT_LAST );
846 
847  /* Allocate the PGP object information */
848  if( ( pgpInfo = clAlloc( "initPrivateFunction", \
849  sizeof( PGP_INFO ) * MAX_PGP_OBJECTS ) ) == NULL )
850  return( CRYPT_ERROR_MEMORY );
851  memset( pgpInfo, 0, sizeof( PGP_INFO ) * MAX_PGP_OBJECTS );
852  keysetInfoPtr->keyData = pgpInfo;
853  keysetInfoPtr->keyDataSize = sizeof( PGP_INFO ) * MAX_PGP_OBJECTS;
854 
855  /* If this is a newly-created keyset, there's nothing left to do */
856  if( options == CRYPT_KEYOPT_CREATE )
857  return( CRYPT_OK );
858 
859  /* Read all of the keys in the keyring */
860  status = pgpReadKeyring( &keysetInfoPtr->keysetFile->stream, pgpInfo,
861  MAX_PGP_OBJECTS, NULL, NULL, KEYSET_ERRINFO );
862  if( status == OK_SPECIAL )
863  {
864  /* We couldn't process one or more packets, make the keyset read-
865  only to ensure that the incomplete key data isn't written to
866  disk */
867  keysetInfoPtr->options = CRYPT_KEYOPT_READONLY;
868  status = CRYPT_OK;
869  }
870  if( cryptStatusError( status ) )
871  keysetInfoPtr->shutdownFunction( keysetInfoPtr );
872  return( status );
873  }
874 
875 /****************************************************************************
876 * *
877 * Keyset Access Routines *
878 * *
879 ****************************************************************************/
880 
882 int setAccessMethodPGPPublic( INOUT KEYSET_INFO *keysetInfoPtr )
883  {
884  assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
885 
886  REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
887  ( keysetInfoPtr->subType == KEYSET_SUBTYPE_PGP_PUBLIC ||
888  keysetInfoPtr->subType == KEYSET_SUBTYPE_PGP_PRIVATE ) );
889 
890  /* Set the access method pointers */
891  keysetInfoPtr->initFunction = initPublicFunction;
892  keysetInfoPtr->shutdownFunction = shutdownFunction;
893  keysetInfoPtr->getItemFunction = getItemFunction;
894  keysetInfoPtr->setItemFunction = setItemFunction;
895 
896  return( CRYPT_OK );
897  }
898 
900 int setAccessMethodPGPPrivate( INOUT KEYSET_INFO *keysetInfoPtr )
901  {
902  assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
903 
904  REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
905  ( keysetInfoPtr->subType == KEYSET_SUBTYPE_PGP_PUBLIC ||
906  keysetInfoPtr->subType == KEYSET_SUBTYPE_PGP_PRIVATE ) );
907 
908  /* Set the access method pointers */
909  keysetInfoPtr->initFunction = initPrivateFunction;
910  keysetInfoPtr->shutdownFunction = shutdownFunction;
911  keysetInfoPtr->getItemFunction = getItemFunction;
912  keysetInfoPtr->setItemFunction = setItemFunction;
913 
914  return( CRYPT_OK );
915  }
916 #endif /* USE_PGPKEYS */