1 /****************************************************************************
2 * *
3 * Internal Key Exchange Routines *
4 * Copyright Peter Gutmann 1993-2007 *
5 * *
6 ****************************************************************************/
7
8 #if defined( INC_ALL )
9 #include "crypt.h"
10 #include "asn1.h"
11 #include "mech.h"
12 #include "pgp.h"
13 #else
14 #include "crypt.h"
15 #include "enc_dec/asn1.h"
16 #include "mechs/mech.h"
17 #include "misc/pgp.h"
18 #endif /* Compiler-specific includes */
19
20 #ifdef USE_INT_CMS
21
22 /****************************************************************************
23 * *
24 * Low-level Key Export Functions *
25 * *
26 ****************************************************************************/
27
28 /* Export a conventionally encrypted session key */
29
30 CHECK_RETVAL STDC_NONNULL_ARG( ( 3 ) ) \
exportConventionalKey(OUT_BUFFER_OPT (encryptedKeyMaxLength,* encryptedKeyLength)void * encryptedKey,IN_DATALENGTH_Z const int encryptedKeyMaxLength,OUT_DATALENGTH_Z int * encryptedKeyLength,IN_HANDLE_OPT const CRYPT_CONTEXT iSessionKeyContext,IN_HANDLE const CRYPT_CONTEXT iExportContext,IN_ENUM (KEYEX)const KEYEX_TYPE keyexType)31 int exportConventionalKey( OUT_BUFFER_OPT( encryptedKeyMaxLength, *encryptedKeyLength ) \
32 void *encryptedKey,
33 IN_DATALENGTH_Z const int encryptedKeyMaxLength,
34 OUT_DATALENGTH_Z int *encryptedKeyLength,
35 IN_HANDLE_OPT const CRYPT_CONTEXT iSessionKeyContext,
36 IN_HANDLE const CRYPT_CONTEXT iExportContext,
37 IN_ENUM( KEYEX ) const KEYEX_TYPE keyexType )
38 {
39 MECHANISM_WRAP_INFO mechanismInfo;
40 const WRITEKEK_FUNCTION writeKeyexFunction = getWriteKekFunction( keyexType );
41 BYTE buffer[ CRYPT_MAX_KEYSIZE + 16 + 8 ];
42 int keySize, ivSize, status;
43
44 assert( ( encryptedKey == NULL && encryptedKeyMaxLength == 0 ) || \
45 isWritePtr( encryptedKey, encryptedKeyMaxLength ) );
46 assert( isWritePtr( encryptedKeyLength, sizeof( int ) ) );
47
48 REQUIRES( ( encryptedKey == NULL && encryptedKeyMaxLength == 0 ) || \
49 ( encryptedKey != NULL && \
50 encryptedKeyMaxLength > MIN_CRYPT_OBJECTSIZE && \
51 encryptedKeyMaxLength < MAX_BUFFER_SIZE ) );
52 REQUIRES( ( keyexType == KEYEX_PGP && \
53 iSessionKeyContext == CRYPT_UNUSED ) || \
54 ( keyexType != KEYEX_PGP && \
55 isHandleRangeValid( iSessionKeyContext ) ) );
56 REQUIRES( isHandleRangeValid( iExportContext ) );
57 REQUIRES( keyexType > KEYEX_NONE && keyexType < KEYEX_LAST );
58
59 /* Clear return value */
60 *encryptedKeyLength = 0;
61
62 /* Make sure that the requested key exchange format is available */
63 if( writeKeyexFunction == NULL )
64 return( CRYPT_ERROR_NOTAVAIL );
65
66 #ifdef USE_PGP
67 /* PGP doesn't actually wrap up a key but derives the session key
68 directly from the password. Because of this there isn't any key
69 wrapping to be done so we just write the key derivation parameters
70 and exit */
71 if( keyexType == KEYEX_PGP )
72 {
73 STREAM stream;
74
75 sMemOpenOpt( &stream, encryptedKey, encryptedKeyMaxLength );
76 status = writeKeyexFunction( &stream, iExportContext, NULL, 0 );
77 if( cryptStatusOK( status ) )
78 *encryptedKeyLength = stell( &stream );
79 sMemDisconnect( &stream );
80
81 return( status );
82 }
83 #endif /* USE_PGP */
84
85 /* Get the export parameters */
86 status = krnlSendMessage( iSessionKeyContext, IMESSAGE_GETATTRIBUTE,
87 &keySize, CRYPT_CTXINFO_KEYSIZE );
88 if( cryptStatusError( status ) )
89 return( cryptArgError( status ) ? CRYPT_ARGERROR_NUM1 : status );
90 if( cryptStatusError( krnlSendMessage( iExportContext,
91 IMESSAGE_GETATTRIBUTE, &ivSize,
92 CRYPT_CTXINFO_IVSIZE ) ) )
93 ivSize = 0;
94
95 /* Load an IV into the exporting context. This is somewhat nasty in that
96 a side-effect of exporting a key is to load an IV, which isn't really
97 part of the function's job description. The alternative would be to
98 require the user to explicitly load an IV before exporting the key,
99 but this is equally nasty because they'll never remember. The lesser
100 of the two evils is to load the IV here and assume that anyone
101 loading the IV themselves will read the docs, which warn about the
102 side-effects of exporting a key.
103
104 Note that we always load a new IV when we export a key because the
105 caller may be using the context to exchange multiple keys. Since each
106 exported key requires its own IV we perform an unconditional reload.
107 In addition because we don't want another thread coming along and
108 changing the IV while we're in the process of encrypting with it, we
109 lock the exporting key object until the encryption has completed and
110 the IV is written to the output */
111 status = krnlSendMessage( iExportContext, IMESSAGE_SETATTRIBUTE,
112 MESSAGE_VALUE_TRUE, CRYPT_IATTRIBUTE_LOCKED );
113 if( cryptStatusError( status ) )
114 return( status );
115 if( ivSize > 0 )
116 {
117 status = krnlSendNotifier( iExportContext, IMESSAGE_CTX_GENIV );
118 if( cryptStatusError( status ) )
119 return( status );
120 }
121
122 /* Encrypt the session key and write the result to the output stream */
123 if( encryptedKey == NULL )
124 {
125 setMechanismWrapInfo( &mechanismInfo, NULL, 0, NULL, 0,
126 iSessionKeyContext, iExportContext );
127 }
128 else
129 {
130 setMechanismWrapInfo( &mechanismInfo, buffer, CRYPT_MAX_KEYSIZE + 16,
131 NULL, 0, iSessionKeyContext, iExportContext );
132 }
133 status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_EXPORT,
134 &mechanismInfo, MECHANISM_ENC_CMS );
135 if( cryptStatusOK( status ) )
136 {
137 STREAM stream;
138
139 /* If we're perfoming a dummy export for a length check, set up a
140 dummy value to write */
141 if( encryptedKey == NULL )
142 memset( buffer, 0x01, mechanismInfo.wrappedDataLength );
143
144 sMemOpenOpt( &stream, encryptedKey, encryptedKeyMaxLength );
145 status = writeKeyexFunction( &stream, iExportContext,
146 ( encryptedKey != NULL ) ? \
147 mechanismInfo.wrappedData : buffer,
148 mechanismInfo.wrappedDataLength );
149 if( cryptStatusOK( status ) )
150 *encryptedKeyLength = stell( &stream );
151 sMemDisconnect( &stream );
152 }
153 ( void ) krnlSendMessage( iExportContext, IMESSAGE_SETATTRIBUTE,
154 MESSAGE_VALUE_FALSE, CRYPT_IATTRIBUTE_LOCKED );
155 clearMechanismInfo( &mechanismInfo );
156 zeroise( buffer, CRYPT_MAX_KEYSIZE + 16 );
157 return( status );
158 }
159
160 /* Export a public-key encrypted session key */
161
162 CHECK_RETVAL STDC_NONNULL_ARG( ( 3 ) ) \
exportPublicKey(OUT_BUFFER_OPT (encryptedKeyMaxLength,* encryptedKeyLength)void * encryptedKey,IN_DATALENGTH_Z const int encryptedKeyMaxLength,OUT_DATALENGTH_Z int * encryptedKeyLength,IN_HANDLE const CRYPT_CONTEXT iSessionKeyContext,IN_HANDLE const CRYPT_CONTEXT iExportContext,IN_BUFFER_OPT (auxInfoLength)const void * auxInfo,IN_LENGTH_SHORT_Z const int auxInfoLength,IN_ENUM (KEYEX)const KEYEX_TYPE keyexType)163 int exportPublicKey( OUT_BUFFER_OPT( encryptedKeyMaxLength, *encryptedKeyLength ) \
164 void *encryptedKey,
165 IN_DATALENGTH_Z const int encryptedKeyMaxLength,
166 OUT_DATALENGTH_Z int *encryptedKeyLength,
167 IN_HANDLE const CRYPT_CONTEXT iSessionKeyContext,
168 IN_HANDLE const CRYPT_CONTEXT iExportContext,
169 IN_BUFFER_OPT( auxInfoLength ) const void *auxInfo,
170 IN_LENGTH_SHORT_Z const int auxInfoLength,
171 IN_ENUM( KEYEX ) const KEYEX_TYPE keyexType )
172 {
173 MECHANISM_WRAP_INFO mechanismInfo;
174 const WRITEKEYTRANS_FUNCTION writeKeytransFunction = getWriteKeytransFunction( keyexType );
175 const BOOLEAN requiresSizeFixup = \
176 ( ( keyexType == KEYEX_CMS || keyexType == KEYEX_CRYPTLIB ) && \
177 ( encryptedKey != NULL ) ) ? TRUE : FALSE;
178 BYTE buffer[ MAX_PKCENCRYPTED_SIZE + 8 ];
179 int exportKeySize DUMMY_INIT, status;
180
181 assert( ( encryptedKey == NULL && encryptedKeyMaxLength == 0 ) || \
182 isWritePtr( encryptedKey, encryptedKeyMaxLength ) );
183 assert( isWritePtr( encryptedKeyLength, sizeof( int ) ) );
184 assert( ( auxInfo == NULL && auxInfoLength == 0 ) || \
185 isReadPtr( auxInfo, auxInfoLength ) );
186
187 REQUIRES( ( encryptedKey == NULL && encryptedKeyMaxLength == 0 ) || \
188 ( encryptedKey != NULL && \
189 encryptedKeyMaxLength > MIN_CRYPT_OBJECTSIZE && \
190 encryptedKeyMaxLength < MAX_BUFFER_SIZE ) );
191 REQUIRES( isHandleRangeValid( iSessionKeyContext ) );
192 REQUIRES( isHandleRangeValid( iExportContext ) );
193 REQUIRES( ( auxInfo == NULL && auxInfoLength == 0 ) || \
194 ( auxInfo != NULL && \
195 auxInfoLength > 0 && auxInfoLength < MAX_INTLENGTH_SHORT ) );
196 REQUIRES( keyexType > KEYEX_NONE && keyexType < KEYEX_LAST );
197
198 /* Clear return value */
199 *encryptedKeyLength = 0;
200
201 /* Make sure that the requested key exchange format is available */
202 if( writeKeytransFunction == NULL )
203 return( CRYPT_ERROR_NOTAVAIL );
204
205 /* Get the export parameters */
206 if( requiresSizeFixup )
207 {
208 status = krnlSendMessage( iExportContext, IMESSAGE_GETATTRIBUTE,
209 &exportKeySize, CRYPT_CTXINFO_KEYSIZE );
210 if( cryptStatusError( status ) )
211 return( cryptArgError( status ) ? CRYPT_ARGERROR_NUM2 : status );
212 if( exportKeySize > encryptedKeyMaxLength )
213 return( CRYPT_ERROR_OVERFLOW );
214 }
215
216 /* Encrypt the session key and write the result to the output stream */
217 if( encryptedKey == NULL )
218 {
219 setMechanismWrapInfo( &mechanismInfo, NULL, 0, NULL, 0,
220 iSessionKeyContext, iExportContext );
221 }
222 else
223 {
224 setMechanismWrapInfo( &mechanismInfo, buffer, MAX_PKCENCRYPTED_SIZE,
225 NULL, 0, iSessionKeyContext, iExportContext );
226 }
227 status = krnlSendMessage( iExportContext, IMESSAGE_DEV_EXPORT,
228 &mechanismInfo, ( keyexType == KEYEX_PGP ) ? \
229 MECHANISM_ENC_PKCS1_PGP : \
230 MECHANISM_ENC_PKCS1 );
231 if( cryptStatusOK( status ) )
232 {
233 STREAM stream;
234
235 /* If we're perfoming a dummy export for a length check, set up a
236 dummy value to write */
237 if( encryptedKey == NULL )
238 {
239 memset( buffer, 0x01, mechanismInfo.wrappedDataLength );
240 mechanismInfo.wrappedData = buffer;
241 }
242
243 /* If we're using the CMS data format then we need to fix up the
244 size of the wrapped key data to match the exporting key size.
245 This is necessary because the higher-level ASN.1 wrappers at the
246 CMS envelope level won't reflect the fact that the size has
247 changed at the CMS keyex level, so we need to adjust the data
248 size to ensure that the amount of data we output matches what
249 was promised in the size check */
250 if( requiresSizeFixup && mechanismInfo.wrappedDataLength < exportKeySize )
251 {
252 const int delta = exportKeySize - mechanismInfo.wrappedDataLength;
253
254 memmove( ( BYTE * ) mechanismInfo.wrappedData + delta,
255 mechanismInfo.wrappedData,
256 mechanismInfo.wrappedDataLength );
257 memset( mechanismInfo.wrappedData, 0, delta );
258 mechanismInfo.wrappedDataLength = exportKeySize;
259 }
260
261 sMemOpenOpt( &stream, encryptedKey, encryptedKeyMaxLength );
262 status = writeKeytransFunction ( &stream, iExportContext,
263 mechanismInfo.wrappedData,
264 mechanismInfo.wrappedDataLength,
265 auxInfo, auxInfoLength );
266 if( cryptStatusOK( status ) )
267 *encryptedKeyLength = stell( &stream );
268 sMemDisconnect( &stream );
269 }
270 clearMechanismInfo( &mechanismInfo );
271
272 /* Clean up */
273 zeroise( buffer, MAX_PKCENCRYPTED_SIZE );
274 return( status );
275 }
276
277 /****************************************************************************
278 * *
279 * Low-level Key Import Functions *
280 * *
281 ****************************************************************************/
282
283 /* Import a conventionally encrypted session key */
284
285 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
importConventionalKey(IN_BUFFER (encryptedKeyLength)const void * encryptedKey,IN_DATALENGTH const int encryptedKeyLength,IN_HANDLE const CRYPT_CONTEXT iSessionKeyContext,IN_HANDLE const CRYPT_CONTEXT iImportContext,IN_ENUM (KEYEX)const KEYEX_TYPE keyexType)286 int importConventionalKey( IN_BUFFER( encryptedKeyLength ) \
287 const void *encryptedKey,
288 IN_DATALENGTH const int encryptedKeyLength,
289 IN_HANDLE const CRYPT_CONTEXT iSessionKeyContext,
290 IN_HANDLE const CRYPT_CONTEXT iImportContext,
291 IN_ENUM( KEYEX ) const KEYEX_TYPE keyexType )
292 {
293 MECHANISM_WRAP_INFO mechanismInfo;
294 const READKEK_FUNCTION readKeyexFunction = getReadKekFunction( keyexType );
295 QUERY_INFO queryInfo;
296 MESSAGE_DATA msgData;
297 STREAM stream;
298 int importAlgo, importMode DUMMY_INIT, status; /* int vs.enum */
299
300 assert( isReadPtr( encryptedKey, encryptedKeyLength ) );
301
302 REQUIRES( encryptedKeyLength > MIN_CRYPT_OBJECTSIZE && \
303 encryptedKeyLength < MAX_BUFFER_SIZE );
304 REQUIRES( isHandleRangeValid( iSessionKeyContext ) );
305 REQUIRES( isHandleRangeValid( iImportContext ) );
306 REQUIRES( keyexType > KEYEX_NONE && keyexType < KEYEX_LAST );
307
308 /* Make sure that the requested key exchange format is available */
309 if( readKeyexFunction == NULL )
310 return( CRYPT_ERROR_NOTAVAIL );
311
312 /* Get the import parameters */
313 status = krnlSendMessage( iImportContext, IMESSAGE_GETATTRIBUTE,
314 &importAlgo, CRYPT_CTXINFO_ALGO );
315 if( cryptStatusOK( status ) )
316 status = krnlSendMessage( iImportContext, IMESSAGE_GETATTRIBUTE,
317 &importMode, CRYPT_CTXINFO_MODE );
318 if( cryptStatusError( status ) )
319 return( cryptArgError( status ) ? CRYPT_ARGERROR_NUM2 : status );
320
321 /* Read and check the encrypted key record and make sure that we'll be
322 using the correct type of encryption context to decrypt it */
323 sMemConnect( &stream, encryptedKey, encryptedKeyLength );
324 status = readKeyexFunction( &stream, &queryInfo );
325 sMemDisconnect( &stream );
326 if( cryptStatusOK( status ) && \
327 ( importAlgo != queryInfo.cryptAlgo || \
328 importMode != queryInfo.cryptMode ) )
329 status = CRYPT_ARGERROR_NUM1;
330 if( cryptStatusError( status ) )
331 {
332 zeroise( &queryInfo, sizeof( QUERY_INFO ) );
333 return( status );
334 }
335
336 /* Extract the encrypted key from the buffer and decrypt it. Since we
337 don't want another thread changing the IV while we're using the import
338 context, we lock it for the duration */
339 status = krnlSendMessage( iImportContext, IMESSAGE_SETATTRIBUTE,
340 MESSAGE_VALUE_TRUE, CRYPT_IATTRIBUTE_LOCKED );
341 if( cryptStatusError( status ) )
342 {
343 zeroise( &queryInfo, sizeof( QUERY_INFO ) );
344 return( status );
345 }
346 if( needsIV( importMode ) && importAlgo != CRYPT_ALGO_RC4 )
347 {
348 setMessageData( &msgData, queryInfo.iv, queryInfo.ivLength );
349 status = krnlSendMessage( iImportContext, IMESSAGE_SETATTRIBUTE_S,
350 &msgData, CRYPT_CTXINFO_IV );
351 if( cryptStatusError( status ) )
352 {
353 ( void ) krnlSendMessage( iImportContext, IMESSAGE_SETATTRIBUTE,
354 MESSAGE_VALUE_FALSE,
355 CRYPT_IATTRIBUTE_LOCKED );
356 zeroise( &queryInfo, sizeof( QUERY_INFO ) );
357 return( status );
358 }
359 }
360 ENSURES( rangeCheck( queryInfo.dataStart, queryInfo.dataLength,
361 encryptedKeyLength ) );
362 setMechanismWrapInfo( &mechanismInfo,
363 ( BYTE * ) encryptedKey + queryInfo.dataStart,
364 queryInfo.dataLength, NULL, 0,
365 iSessionKeyContext, iImportContext );
366 status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_IMPORT,
367 &mechanismInfo, MECHANISM_ENC_CMS );
368 ( void ) krnlSendMessage( iImportContext, IMESSAGE_SETATTRIBUTE,
369 MESSAGE_VALUE_FALSE,
370 CRYPT_IATTRIBUTE_LOCKED );
371 clearMechanismInfo( &mechanismInfo );
372 zeroise( &queryInfo, sizeof( QUERY_INFO ) );
373
374 return( status );
375 }
376
377 /* Import a public-key encrypted session key */
378
379 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
importPublicKey(IN_BUFFER (encryptedKeyLength)const void * encryptedKey,IN_DATALENGTH const int encryptedKeyLength,IN_HANDLE_OPT const CRYPT_CONTEXT iSessionKeyContext,IN_HANDLE const CRYPT_CONTEXT iImportContext,OUT_OPT_HANDLE_OPT CRYPT_CONTEXT * iReturnedContext,IN_ENUM (KEYEX)const KEYEX_TYPE keyexType)380 int importPublicKey( IN_BUFFER( encryptedKeyLength ) const void *encryptedKey,
381 IN_DATALENGTH const int encryptedKeyLength,
382 IN_HANDLE_OPT const CRYPT_CONTEXT iSessionKeyContext,
383 IN_HANDLE const CRYPT_CONTEXT iImportContext,
384 OUT_OPT_HANDLE_OPT CRYPT_CONTEXT *iReturnedContext,
385 IN_ENUM( KEYEX ) const KEYEX_TYPE keyexType )
386 {
387 MECHANISM_WRAP_INFO mechanismInfo;
388 const READKEYTRANS_FUNCTION readKeytransFunction = getReadKeytransFunction( keyexType );
389 QUERY_INFO queryInfo;
390 MESSAGE_DATA msgData;
391 STREAM stream;
392 int compareType, status;
393
394 assert( isReadPtr( encryptedKey, encryptedKeyLength ) );
395 assert( ( keyexType == KEYEX_PGP && \
396 isWritePtr( iReturnedContext, sizeof( CRYPT_CONTEXT ) ) ) || \
397 ( keyexType != KEYEX_PGP && iReturnedContext == NULL ) );
398
399 REQUIRES( encryptedKeyLength > MIN_CRYPT_OBJECTSIZE && \
400 encryptedKeyLength < MAX_BUFFER_SIZE );
401 REQUIRES( ( keyexType == KEYEX_PGP && \
402 iSessionKeyContext == CRYPT_UNUSED ) || \
403 ( keyexType != KEYEX_PGP && \
404 isHandleRangeValid( iSessionKeyContext ) ) );
405 REQUIRES( isHandleRangeValid( iImportContext ) );
406 REQUIRES( ( keyexType == KEYEX_PGP && iReturnedContext != NULL ) || \
407 ( keyexType != KEYEX_PGP && iReturnedContext == NULL ) );
408 REQUIRES( keyexType > KEYEX_NONE && keyexType < KEYEX_LAST );
409
410 /* Clear return value */
411 if( iReturnedContext != NULL )
412 *iReturnedContext = CRYPT_ERROR;
413
414 /* Make sure that the requested key exchange format is available */
415 if( readKeytransFunction == NULL )
416 return( CRYPT_ERROR_NOTAVAIL );
417
418 /* Read and check the encrypted key record */
419 sMemConnect( &stream, encryptedKey, encryptedKeyLength );
420 status = readKeytransFunction( &stream, &queryInfo );
421 sMemDisconnect( &stream );
422 if( cryptStatusError( status ) )
423 {
424 zeroise( &queryInfo, sizeof( QUERY_INFO ) );
425 return( status );
426 }
427
428 /* Make sure that we've been given the correct key */
429 setMessageData( &msgData, queryInfo.keyID, queryInfo.keyIDlength );
430 switch( keyexType )
431 {
432 case KEYEX_CMS:
433 setMessageData( &msgData, \
434 ( BYTE * ) encryptedKey + queryInfo.iAndSStart, \
435 queryInfo.iAndSLength );
436 compareType = MESSAGE_COMPARE_ISSUERANDSERIALNUMBER;
437 break;
438
439 case KEYEX_CRYPTLIB:
440 compareType = MESSAGE_COMPARE_KEYID;
441 break;
442
443 case KEYEX_PGP:
444 compareType = ( queryInfo.version == PGP_VERSION_2 ) ? \
445 MESSAGE_COMPARE_KEYID_PGP : \
446 MESSAGE_COMPARE_KEYID_OPENPGP;
447 break;
448
449 default:
450 retIntError();
451 }
452 status = krnlSendMessage( iImportContext, IMESSAGE_COMPARE, &msgData,
453 compareType );
454 if( cryptStatusError( status ) && \
455 compareType == MESSAGE_COMPARE_KEYID )
456 {
457 /* Checking for the keyID gets a bit complicated, in theory it's the
458 subjectKeyIdentifier from a certificate but in practice this form
459 is mostly used for certificateless public keys. Because of this we
460 check for the keyID first and if that fails fall back to the
461 sKID */
462 status = krnlSendMessage( iImportContext, IMESSAGE_COMPARE,
463 &msgData,
464 MESSAGE_COMPARE_SUBJECTKEYIDENTIFIER );
465 }
466 if( cryptStatusError( status ) && \
467 compareType == MESSAGE_COMPARE_KEYID_OPENPGP )
468 {
469 /* Some broken PGP implementations put PGP 2.x IDs in packets marked
470 as OpenPGP packets so if we were doing a check for an OpenPGP ID
471 and it failed, fall back to a PGP 2.x one */
472 status = krnlSendMessage( iImportContext, IMESSAGE_COMPARE,
473 &msgData, MESSAGE_COMPARE_KEYID_PGP );
474 }
475 if( cryptStatusError( status ) )
476 {
477 /* A failed comparison is reported as a generic CRYPT_ERROR, convert
478 it into a wrong-key error */
479 zeroise( &queryInfo, sizeof( QUERY_INFO ) );
480 return( CRYPT_ERROR_WRONGKEY );
481 }
482
483 /* Decrypt the encrypted key and load it into the context */
484 if( keyexType != KEYEX_PGP )
485 {
486 setMechanismWrapInfo( &mechanismInfo,
487 ( BYTE * ) encryptedKey + queryInfo.dataStart,
488 queryInfo.dataLength, NULL, 0,
489 iSessionKeyContext, iImportContext );
490 status = krnlSendMessage( iImportContext, IMESSAGE_DEV_IMPORT,
491 &mechanismInfo, MECHANISM_ENC_PKCS1 );
492 }
493 else
494 {
495 /* PGP doesn't provide separate session key information with the
496 encrypted data but wraps it up alongside the encrypted key, so we
497 can't import the wrapped key into a context via the standard key
498 import functions but instead have to create the context as part
499 of the unwrap process */
500 setMechanismWrapInfo( &mechanismInfo,
501 ( BYTE * ) encryptedKey + queryInfo.dataStart,
502 queryInfo.dataLength, NULL, 0,
503 CRYPT_UNUSED, iImportContext );
504 status = krnlSendMessage( iImportContext, IMESSAGE_DEV_IMPORT,
505 &mechanismInfo, MECHANISM_ENC_PKCS1_PGP );
506 if( cryptStatusOK( status ) )
507 *iReturnedContext = mechanismInfo.keyContext;
508 }
509 clearMechanismInfo( &mechanismInfo );
510 zeroise( &queryInfo, sizeof( QUERY_INFO ) );
511
512 return( status );
513 }
514 #endif /* USE_INT_CMS */
515