cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
mech_privk.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib Private-Key Wrap Mechanism Routines *
4 * Copyright Peter Gutmann 1992-2008 *
5 * *
6 ****************************************************************************/
7 
8 #ifdef INC_ALL
9  #include "crypt.h"
10  #include "asn1.h"
11  #include "misc_rw.h"
12  #include "stream.h"
13  #include "mech_int.h"
14  #include "pgp.h"
15 #else
16  #include "crypt.h"
17  #include "enc_dec/asn1.h"
18  #include "enc_dec/misc_rw.h"
19  #include "io/stream.h"
20  #include "mechs/mech_int.h"
21  #include "misc/pgp.h"
22 #endif /* Compiler-specific includes */
23 
24 /****************************************************************************
25 * *
26 * Utility Routines *
27 * *
28 ****************************************************************************/
29 
30 #if defined( USE_PGP ) || defined( USE_PGPKEYS )
31 
32 /* Decrypt a PGP MPI */
33 
35 static int pgpReadDecryptMPI( INOUT STREAM *stream,
37  IN_LENGTH_PKC const int minLength,
38  IN_LENGTH_PKC const int maxLength )
39  {
40  void *mpiDataPtr = DUMMY_INIT_PTR;
41  const long mpiDataStartPos = stell( stream ) + UINT16_SIZE;
42  int mpiLength, dummy, status;
43 
44  assert( isWritePtr( stream, sizeof( STREAM ) ) );
45 
46  REQUIRES( isHandleRangeValid( iCryptContext ) );
47  REQUIRES( minLength >= bitsToBytes( 155 ) && \
48  minLength <= maxLength && \
49  maxLength <= CRYPT_MAX_PKCSIZE );
50 
51  /* Get the MPI length and decrypt the payload data. We have to be
52  careful how we handle this because readInteger16Ubits() returns the
53  canonicalised form of the values (with leading zeroes truncated) so
54  the returned length value doesn't necessarily represent the amount
55  of data that we need to decrypt:
56 
57  startPos dataStart stell()
58  | | |
59  v v <-- length -->v
60  +---+-----------+---------------+
61  | | |///////////////| Stream
62  +---+-----------+---------------+ */
63  status = readInteger16Ubits( stream, NULL, &dummy, minLength,
64  maxLength );
65  if( cryptStatusError( status ) )
66  return( status );
67  mpiLength = stell( stream ) - mpiDataStartPos;
68  status = sMemGetDataBlockAbs( stream, mpiDataStartPos, &mpiDataPtr,
69  mpiLength );
70  if( cryptStatusOK( status ) )
71  status = krnlSendMessage( iCryptContext, IMESSAGE_CTX_DECRYPT,
72  mpiDataPtr, mpiLength );
73  return( status );
74  }
75 
76 /* The PGP 2.x key wrap encrypts only the MPI payload data rather than the
77  entire private key record so we have to read and then decrypt each
78  component separately. This is a horrible way to handle things because we
79  have to repeatedly process the MPI data, first in the PGP keyring code to
80  find out how much key data is present, then again during decryption to
81  find the MPI payload that needs to be decrypted, and finally again after
82  decryption to find the MPI payload that needs to be checksummed (although
83  we can shortcut the latter, see the comment in checkPgp2KeyIntegrity().
84 
85  Unfortunately we can't use the xxxPARAM_MIN_x / xxxPARAM_MAX_x values to
86  perform range checking since they're only visible to the context-
87  manipulation code, so we have to use approximations here (the actual
88  values will be checked by the keyload code anyway, it just means that we
89  can't perform very precise pre-filtering here) */
90 
91 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
92 static int pgp2DecryptKey( IN_BUFFER( dataLength ) const void *data,
93  IN_LENGTH_SHORT_MIN( 16 ) const int dataLength,
94  OUT_LENGTH_SHORT_Z int *bytesToChecksum,
95  IN_HANDLE const CRYPT_CONTEXT iCryptContext,
96  const BOOLEAN isDlpAlgo )
97  {
98  STREAM stream;
99  int status;
100 
101  assert( isReadPtr( data, dataLength ) );
102  assert( isWritePtr( bytesToChecksum, sizeof( int ) ) );
103 
104  REQUIRES( dataLength >= 16 && \
105  dataLength < MAX_INTLENGTH_SHORT );
106  REQUIRES( isHandleRangeValid( iCryptContext ) );
107 
108  /* Clear return value */
109  *bytesToChecksum = 0;
110 
111  sMemConnect( &stream, data, dataLength );
112  status = pgpReadDecryptMPI( &stream, iCryptContext, /* d or x */
113  bitsToBytes( 155 ), CRYPT_MAX_PKCSIZE );
114  if( isDlpAlgo )
115  {
116  if( cryptStatusOK( status ) )
117  *bytesToChecksum = stell( &stream );
118  sMemDisconnect( &stream );
119  return( status );
120  }
121  if( cryptStatusOK( status ) )
122  status = pgpReadDecryptMPI( &stream, iCryptContext, /* p */
124  if( cryptStatusOK( status ) )
125  status = pgpReadDecryptMPI( &stream, iCryptContext, /* q */
127  if( cryptStatusOK( status ) )
128  status = pgpReadDecryptMPI( &stream, iCryptContext, /* u */
130  if( cryptStatusOK( status ) )
131  *bytesToChecksum = stell( &stream );
132  sMemDisconnect( &stream );
133  return( status );
134  }
135 #endif /* USE_PGP || USE_PGPKEYS */
136 
137 /* Check that the unwrapped data hasn't been corrupted */
138 
140 static int checkKeyIntegrity( IN_BUFFER( dataLength ) const void *data,
142  const int dataLength,
143  IN_RANGE( 8, CRYPT_MAX_IVSIZE ) \
144  const int blockSize )
145  {
146  const BYTE *padPtr;
147  int length, padSize, i, status;
148 
149  assert( isReadPtr( data, dataLength ) );
150 
151  REQUIRES( dataLength >= MIN_PRIVATE_KEYSIZE && \
152  dataLength < MAX_INTLENGTH_SHORT );
153  REQUIRES( blockSize >= 8 && blockSize <= CRYPT_MAX_IVSIZE );
154 
155  /* Get the length of the encapsulated ASN.1 object */
156  status = getObjectLength( data, dataLength, &length );
157  if( cryptStatusError( status ) )
158  {
159  return( ( status == CRYPT_ERROR_BADDATA ) ? \
160  CRYPT_ERROR_WRONGKEY : status );
161  }
162 
163  /* Check that the PKCS #5 padding is as expected. Performing the check
164  this way is the reverse of the way that it's usually done because we
165  already know the payload size from the ASN.1 and can use this to
166  determine the expected padding value and thus check that the end of
167  the encrypted data hasn't been subject to a bit-flipping attack. For
168  example for RSA private keys the end of the data is:
169 
170  [ INTEGER u ][ INTEGER keySize ][ padding ]
171 
172  where the keySize is encoded as a 4-byte value and the padding is 1-8
173  bytes. If the low bits of u are flipped there's a 5/8 chance that
174  either the keySize value (checked in the RSA read code) or padding
175  will be messed up, both of which will be detected (in addition the
176  RSA key load checks try and verify u when the key is loaded). For
177  DLP keys the end of the data is:
178 
179  [ INTEGER x ][ padding ]
180 
181  for which bit flipping is rather harder to detect since 7/8 of the
182  time the following block won't be affected, however the DLP key load
183  checks also verify x when the key is loaded. The padding checking is
184  effectively free and helps make Klima-Rosa type attacks harder */
185  padPtr = ( const BYTE * ) data + length;
186  padSize = blockSize - ( length & ( blockSize - 1 ) );
187  if( padSize < 1 || padSize > CRYPT_MAX_IVSIZE || \
188  length + padSize > dataLength )
189  return( CRYPT_ERROR_BADDATA );
190  for( i = 0; i < padSize; i++ )
191  {
192  if( padPtr[ i ] != padSize )
193  return( CRYPT_ERROR_BADDATA );
194  }
195 
196  return( CRYPT_OK );
197  }
198 
199 #if defined( USE_PGP ) || defined( USE_PGPKEYS )
200 
202 static int checkPgp2KeyIntegrity( IN_BUFFER( dataLength ) const void *data,
203  IN_LENGTH_SHORT_MIN( 16 ) const int dataLength,
204  IN_LENGTH_SHORT_MIN( 16 ) const int keyDataLength,
205  const BOOLEAN isDlpAlgo )
206  {
207  STREAM stream;
208  const BYTE *keyData = data;
209  int checksum = 0, storedChecksum, i, status;
210 
211  assert( isReadPtr( data, dataLength ) );
212 
213  REQUIRES( dataLength >= 16 && dataLength < MAX_INTLENGTH_SHORT );
214  REQUIRES( keyDataLength >= 16 && \
215  keyDataLength + UINT16_SIZE <= dataLength && \
216  keyDataLength < MAX_INTLENGTH_SHORT );
217 
218  /* Calculate the checksum for the MPIs. In theory we'd have to process
219  them all over again but the checksumming procedure is inconsistent
220  with the encryption in that only the MPI data is encrypted but the
221  overall length and data are checksummed. Since these data blocks are
222  stored consecutively in memory we can checksum all MPI data as one
223  continuous block */
224  for( i = 0; i < keyDataLength; i++ )
225  checksum += keyData[ i ];
226 
227  /* Recover the stored checksum that follows the MPI data and compare it
228  to the calculated checksum */
229  sMemConnect( &stream, keyData + keyDataLength, dataLength - keyDataLength );
230  status = storedChecksum = readUint16( &stream );
231  sMemDisconnect( &stream );
232  if( cryptStatusError( status ) || checksum != storedChecksum )
233  return( CRYPT_ERROR_WRONGKEY );
234  return( CRYPT_OK );
235  }
236 
238 static int checkOpenPgpKeyIntegrity( IN_BUFFER( dataLength ) const void *data,
239  IN_LENGTH_SHORT_MIN( 16 ) const int dataLength )
240  {
241  HASHFUNCTION_ATOMIC hashFunctionAtomic;
243  const BYTE *hashValuePtr;
244  int hashSize;
245 
246  assert( isReadPtr( data, dataLength ) );
247 
248  REQUIRES( dataLength >= 16 && dataLength < MAX_INTLENGTH_SHORT );
249 
250  /* Get the hash algorithm info and make sure that there's room for
251  minimal-length data and the checksum */
252  getHashAtomicParameters( CRYPT_ALGO_SHA1, 0, &hashFunctionAtomic,
253  &hashSize );
254  if( dataLength < bitsToBytes( 155 ) + hashSize )
255  return( CRYPT_ERROR_BADDATA );
256  hashValuePtr = ( const BYTE * ) data + dataLength - hashSize;
257 
258  /* Hash the data and make sure that it matches the stored MDC */
259  hashFunctionAtomic( hashValue, CRYPT_MAX_HASHSIZE, data,
260  dataLength - hashSize );
261  if( !compareDataConstTime( hashValue, hashValuePtr, hashSize ) )
262  return( CRYPT_ERROR_WRONGKEY );
263 
264  return( CRYPT_OK );
265  }
266 #endif /* USE_PGP || USE_PGPKEYS */
267 
268 /****************************************************************************
269 * *
270 * PKCS #15 Private Key Wrap/Unwrap Mechanisms *
271 * *
272 ****************************************************************************/
273 
274 /* Perform private key wrapping/unwrapping. There are several variations of
275  this that are handled through common private key wrap mechanism
276  functions */
277 
280 
282 static int privateKeyWrap( STDC_UNUSED void *dummy,
284  IN_ENUM( PRIVATEKEY_WRAP ) \
285  const PRIVATEKEY_WRAP_TYPE type )
286  {
287  const KEYFORMAT_TYPE formatType = ( type == PRIVATEKEY_WRAP_NORMAL ) ? \
289  STREAM stream;
290  int payloadSize = DUMMY_INIT, blockSize, padSize, status;
291 
292  UNUSED_ARG( dummy );
293 
294  assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_WRAP_INFO ) ) );
295 
297 
298  /* Clear return value */
299  if( mechanismInfo->wrappedData != NULL )
300  {
301  memset( mechanismInfo->wrappedData, 0,
302  mechanismInfo->wrappedDataLength );
303  }
304 
305  /* Get the payload details */
306  sMemNullOpen( &stream );
307  status = exportPrivateKeyData( &stream, mechanismInfo->keyContext,
308  formatType, "private_key", 11 );
309  if( cryptStatusOK( status ) )
310  payloadSize = stell( &stream );
311  sMemClose( &stream );
312  if( cryptStatusError( status ) )
313  return( status );
314  status = krnlSendMessage( mechanismInfo->wrapContext,
315  IMESSAGE_GETATTRIBUTE, &blockSize,
317  if( cryptStatusError( status ) )
318  return( status );
319  padSize = roundUp( payloadSize + 1, blockSize ) - payloadSize;
320 
321  ENSURES( !( ( payloadSize + padSize ) & ( blockSize - 1 ) ) );
322  ENSURES( padSize >= 1 && padSize <= CRYPT_MAX_IVSIZE );
323 
324  /* If this is just a length check, we're done */
325  if( mechanismInfo->wrappedData == NULL )
326  {
327  mechanismInfo->wrappedDataLength = payloadSize + padSize;
328  return( CRYPT_OK );
329  }
330  ANALYSER_HINT( mechanismInfo->wrappedDataLength > MIN_PKCSIZE && \
331  mechanismInfo->wrappedDataLength < MAX_INTLENGTH_SHORT );
332 
333  /* Make sure that the wrapped key fits in the output buffer */
334  if( payloadSize + padSize > mechanismInfo->wrappedDataLength )
335  return( CRYPT_ERROR_OVERFLOW );
336 
337  /* Write the private key data, PKCS #5-pad it, and encrypt it */
338  sMemOpen( &stream, mechanismInfo->wrappedData,
339  mechanismInfo->wrappedDataLength );
340  status = exportPrivateKeyData( &stream, mechanismInfo->keyContext,
341  formatType, "private_key", 11 );
342  sMemDisconnect( &stream );
343  if( cryptStatusOK( status ) )
344  {
345  BYTE startSample[ 8 + 8 ], endSample[ 8 + 8 ];
346  BYTE *dataPtr = mechanismInfo->wrappedData;
347  const void *dataEndPtr = dataPtr + payloadSize + padSize - 8;
348  int i;
349 
350  /* Sample the first and last 8 bytes of data so that we can check
351  that they really have been encrypted */
352  memcpy( startSample, dataPtr, 8 );
353  memcpy( endSample, dataEndPtr, 8 );
354 
355  /* Add the PKCS #5 padding and encrypt the data */
356  for( i = 0; i < padSize; i++ )
357  dataPtr[ payloadSize + i ] = intToByte( padSize );
358  status = krnlSendMessage( mechanismInfo->wrapContext,
360  mechanismInfo->wrappedData,
361  payloadSize + padSize );
362 
363  /* Make sure that the original data samples differ from the final
364  data. We don't perform a retIntError() exit at this point because
365  we need to continue and zeroise the data that we're working with */
366  if( cryptStatusOK( status ) && \
367  ( !memcmp( startSample, dataPtr, 8 ) || \
368  !memcmp( endSample, dataEndPtr, 8 ) ) )
369  {
370  DEBUG_DIAG(( "Failed to encrypt private-key data" ));
371  assert( DEBUG_WARN );
372  status = CRYPT_ERROR_FAILED;
373  }
374  zeroise( startSample, 8 );
375  zeroise( endSample, 8 );
376  }
377  if( cryptStatusError( status ) )
378  {
379  zeroise( mechanismInfo->wrappedData,
380  mechanismInfo->wrappedDataLength );
381  return( status );
382  }
383  mechanismInfo->wrappedDataLength = payloadSize + padSize;
384 
385  return( CRYPT_OK );
386  }
387 
389 static int privateKeyUnwrap( STDC_UNUSED void *dummy,
390  INOUT MECHANISM_WRAP_INFO *mechanismInfo,
391  IN_ENUM( PRIVATEKEY_WRAP ) \
392  const PRIVATEKEY_WRAP_TYPE type )
393  {
394  const KEYFORMAT_TYPE formatType = ( type == PRIVATEKEY_WRAP_NORMAL ) ? \
396  void *buffer;
397  int blockSize, status, altStatus;
398 
399  UNUSED_ARG( dummy );
400 
401  assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_WRAP_INFO ) ) );
402 
404 
405  /* Make sure that the data has a sane length and is a multiple of the
406  cipher block size. Since we force the use of CBC mode we know that
407  it has to have this property. Any required length checks have
408  already been enforced by the kernel ACLs */
409  status = krnlSendMessage( mechanismInfo->wrapContext,
410  IMESSAGE_GETATTRIBUTE, &blockSize,
412  if( cryptStatusError( status ) )
413  return( status );
414  if( mechanismInfo->wrappedDataLength & ( blockSize - 1 ) )
415  return( CRYPT_ERROR_BADDATA );
416 
417  /* Copy the encrypted private key data to a temporary pagelocked buffer,
418  decrypt it, and read it into the context. If we get a corrupted-data
419  error then it's far more likely to be because we decrypted with the
420  wrong key than because any data was corrupted so we convert it to a
421  wrong-key error */
422  if( ( status = krnlMemalloc( &buffer, \
423  mechanismInfo->wrappedDataLength ) ) != CRYPT_OK )
424  return( status );
425  memcpy( buffer, mechanismInfo->wrappedData,
426  mechanismInfo->wrappedDataLength );
427  status = krnlSendMessage( mechanismInfo->wrapContext,
428  IMESSAGE_CTX_DECRYPT, buffer,
429  mechanismInfo->wrappedDataLength );
430  if( cryptStatusOK( status ) )
431  {
432  status = checkKeyIntegrity( buffer,
433  mechanismInfo->wrappedDataLength,
434  blockSize );
435  }
436  if( cryptStatusOK( status ) )
437  {
438  STREAM stream;
439 
440  sMemConnect( &stream, buffer, mechanismInfo->wrappedDataLength );
441  status = importPrivateKeyData( &stream, mechanismInfo->keyContext,
442  formatType );
443  sMemDisconnect( &stream );
444  }
445  zeroise( buffer, mechanismInfo->wrappedDataLength );
446  altStatus = krnlMemfree( &buffer );
447  ENSURES( cryptStatusOK( altStatus ) );
448 
449  return( status );
450  }
451 
453 int exportPrivateKey( STDC_UNUSED void *dummy,
454  INOUT MECHANISM_WRAP_INFO *mechanismInfo )
455  {
456  assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_WRAP_INFO ) ) );
457 
458  return( privateKeyWrap( dummy, mechanismInfo, PRIVATEKEY_WRAP_NORMAL ) );
459  }
460 
462 int importPrivateKey( STDC_UNUSED void *dummy,
463  INOUT MECHANISM_WRAP_INFO *mechanismInfo )
464  {
465  assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_WRAP_INFO ) ) );
466 
467  return( privateKeyUnwrap( dummy, mechanismInfo, PRIVATEKEY_WRAP_NORMAL ) );
468  }
469 
471 int exportPrivateKeyPKCS8( STDC_UNUSED void *dummy,
472  INOUT MECHANISM_WRAP_INFO *mechanismInfo )
473  {
474  assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_WRAP_INFO ) ) );
475 
476  return( privateKeyWrap( dummy, mechanismInfo, PRIVATEKEY_WRAP_OLD ) );
477  }
478 
480 int importPrivateKeyPKCS8( STDC_UNUSED void *dummy,
481  INOUT MECHANISM_WRAP_INFO *mechanismInfo )
482  {
483  assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_WRAP_INFO ) ) );
484 
485  return( privateKeyUnwrap( dummy, mechanismInfo, PRIVATEKEY_WRAP_OLD ) );
486  }
487 
488 /****************************************************************************
489 * *
490 * PGP Private Key Wrap/Unwrap Mechanisms *
491 * *
492 ****************************************************************************/
493 
494 #ifdef USE_PGPKEYS
495 
496 /* Perform PGP private key wrapping/unwrapping. There are several variations
497  of this that are handled through common private key wrap mechanism
498  functions. The variations are:
499 
500  PGP2: mpi_enc( d ), mpi_enc( p ), mpi_enc( q ), mpi_enc( u ),
501  uint16 checksum
502 
503  OpenPGP_Old: enc( mpi [...],
504  uint16 checksum )
505 
506  OpenPGP: enc( mpi [...],
507  byte[20] mdc ) */
508 
509 typedef enum { PRIVATEKEYPGP_WRAP_NONE, PRIVATEKEYPGP_WRAP_PGP2,
510  PRIVATEKEYPGP_WRAP_OPENPGP_OLD,
511  PRIVATEKEYPGP_WRAP_OPENPGP,
512  PRIVATEKEYPGP_WRAP_LAST } PRIVATEKEYPGP_WRAP_TYPE;
513 
514 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
515 static int privateKeyUnwrapPGP( STDC_UNUSED void *dummy,
516  INOUT MECHANISM_WRAP_INFO *mechanismInfo,
517  IN_ENUM( PRIVATEKEYPGP_WRAP ) \
518  const PRIVATEKEYPGP_WRAP_TYPE type )
519  {
520  STREAM stream;
521  void *buffer;
522  int pkcAlgorithm, bytesToChecksum = DUMMY_INIT, status, altStatus;
523 
524  UNUSED_ARG( dummy );
525 
526  assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_WRAP_INFO ) ) );
527 
528  REQUIRES( type > PRIVATEKEYPGP_WRAP_NONE && \
529  type < PRIVATEKEYPGP_WRAP_LAST );
530 
531  /* Get various algorithm parameters */
532  status = krnlSendMessage( mechanismInfo->keyContext,
533  IMESSAGE_GETATTRIBUTE, &pkcAlgorithm,
535  if( cryptStatusError( status ) )
536  return( status );
537 
538  /* Copy the encrypted private key data to a temporary buffer and decrypt
539  it */
540  if( ( status = krnlMemalloc( &buffer, \
541  mechanismInfo->wrappedDataLength ) ) != CRYPT_OK )
542  return( status );
543  memcpy( buffer, mechanismInfo->wrappedData,
544  mechanismInfo->wrappedDataLength );
545  if( type == PRIVATEKEYPGP_WRAP_PGP2 )
546  {
547  status = pgp2DecryptKey( buffer, mechanismInfo->wrappedDataLength,
548  &bytesToChecksum, mechanismInfo->wrapContext,
549  ( pkcAlgorithm != CRYPT_ALGO_RSA ) ? \
550  TRUE : FALSE );
551  }
552  else
553  {
554  status = krnlSendMessage( mechanismInfo->wrapContext,
555  IMESSAGE_CTX_DECRYPT, buffer,
556  mechanismInfo->wrappedDataLength );
557  }
558  if( cryptStatusError( status ) )
559  {
560  zeroise( buffer, mechanismInfo->wrappedDataLength );
561  altStatus = krnlMemfree( &buffer );
562  ENSURES( cryptStatusOK( altStatus ) );
563  return( status );
564  }
565 
566  /* Perform one of PGP's assorted key checksumming operations and read
567  the key data into the context */
568  if( type == PRIVATEKEYPGP_WRAP_PGP2 || \
569  type == PRIVATEKEYPGP_WRAP_OPENPGP_OLD )
570  {
571  /* Before the use of MDCs for private-key data there was a mutant
572  halfway stage that used the PGP 2.x checksum but encrypted all of
573  the key data in the OpenPGP manner. If we're using this halfway
574  variant then the amount of data to checksum is the total amount
575  minus the size of the checksum */
576  if( type == PRIVATEKEYPGP_WRAP_OPENPGP_OLD )
577  bytesToChecksum = mechanismInfo->wrappedDataLength - UINT16_SIZE;
578  status = checkPgp2KeyIntegrity( buffer, mechanismInfo->wrappedDataLength,
579  bytesToChecksum,
580  ( pkcAlgorithm != CRYPT_ALGO_RSA ) ? \
581  TRUE : FALSE );
582  }
583  else
584  {
585  status = checkOpenPgpKeyIntegrity( buffer,
586  mechanismInfo->wrappedDataLength );
587  }
588  if( cryptStatusOK( status ) )
589  {
590  sMemConnect( &stream, buffer, mechanismInfo->wrappedDataLength );
591  status = importPrivateKeyData( &stream, mechanismInfo->keyContext,
592  KEYFORMAT_PGP );
593  sMemDisconnect( &stream );
594  if( status == CRYPT_ERROR_BADDATA )
595  status = CRYPT_ERROR_WRONGKEY;
596  }
597  zeroise( buffer, mechanismInfo->wrappedDataLength );
598  altStatus = krnlMemfree( &buffer );
599  ENSURES( cryptStatusOK( altStatus ) );
600 
601  return( status );
602  }
603 
605 int importPrivateKeyPGP2( STDC_UNUSED void *dummy,
606  INOUT MECHANISM_WRAP_INFO *mechanismInfo )
607  {
608  assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_WRAP_INFO ) ) );
609 
610  return( privateKeyUnwrapPGP( dummy, mechanismInfo,
611  PRIVATEKEYPGP_WRAP_PGP2 ) );
612  }
613 
615 int importPrivateKeyOpenPGPOld( STDC_UNUSED void *dummy,
616  INOUT MECHANISM_WRAP_INFO *mechanismInfo )
617  {
618  assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_WRAP_INFO ) ) );
619 
620  return( privateKeyUnwrapPGP( dummy, mechanismInfo,
621  PRIVATEKEYPGP_WRAP_OPENPGP_OLD ) );
622  }
623 
625 int importPrivateKeyOpenPGP( STDC_UNUSED void *dummy,
626  INOUT MECHANISM_WRAP_INFO *mechanismInfo )
627  {
628  assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_WRAP_INFO ) ) );
629 
630  return( privateKeyUnwrapPGP( dummy, mechanismInfo,
631  PRIVATEKEYPGP_WRAP_OPENPGP ) );
632  }
633 #endif /* USE_PGPKEYS */