1 /****************************************************************************
2 * *
3 * 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 "asn1_ext.h"
12 #include "misc_rw.h"
13 #include "pgp_rw.h"
14 #include "mech.h"
15 #else
16 #include "crypt.h"
17 #include "enc_dec/asn1.h"
18 #include "enc_dec/asn1_ext.h"
19 #include "enc_dec/misc_rw.h"
20 #include "enc_dec/pgp_rw.h"
21 #include "mechs/mech.h"
22 #endif /* Compiler-specific includes */
23
24 #ifdef USE_INT_CMS
25
26 /****************************************************************************
27 * *
28 * Utility Functions *
29 * *
30 ****************************************************************************/
31
32 /* Try and determine the format of the encrypted data */
33
34 CHECK_RETVAL_ENUM( CRYPT_FORMAT ) STDC_NONNULL_ARG( ( 1 ) ) \
getFormatType(IN_BUFFER (dataLength)const void * data,IN_DATALENGTH const int dataLength)35 static CRYPT_FORMAT_TYPE getFormatType( IN_BUFFER( dataLength ) const void *data,
36 IN_DATALENGTH const int dataLength )
37 {
38 STREAM stream;
39 long value;
40 int status;
41
42 assert( isReadPtr( data, dataLength ) );
43
44 REQUIRES_EXT( dataLength > MIN_CRYPT_OBJECTSIZE && \
45 dataLength < MAX_BUFFER_SIZE, CRYPT_FORMAT_NONE );
46
47 sMemConnect( &stream, data, min( 16, dataLength ) );
48
49 /* Figure out what we've got. PKCS #7/CMS/SMIME keyTrans begins:
50
51 keyTransRecipientInfo ::= SEQUENCE {
52 version INTEGER (0|2),
53
54 while a kek begins:
55
56 kekRecipientInfo ::= [3] IMPLICIT SEQUENCE {
57 version INTEGER (0),
58
59 which allows us to determine which type of object we have. Note that
60 we use sPeek() rather than peekTag() because we want to continue
61 processing (or at least checking for) PGP data if it's no ASN.1 */
62 if( sPeek( &stream ) == BER_SEQUENCE )
63 {
64 CRYPT_FORMAT_TYPE formatType;
65
66 readSequence( &stream, NULL );
67 status = readShortInteger( &stream, &value );
68 if( cryptStatusError( status ) )
69 {
70 sMemDisconnect( &stream );
71 return( CRYPT_FORMAT_NONE );
72 }
73 switch( value )
74 {
75 case KEYTRANS_VERSION:
76 formatType = CRYPT_FORMAT_CMS;
77 break;
78
79 case KEYTRANS_EX_VERSION:
80 formatType = CRYPT_FORMAT_CRYPTLIB;
81 break;
82
83 default:
84 formatType = CRYPT_FORMAT_NONE;
85 }
86 sMemDisconnect( &stream );
87
88 return( formatType );
89 }
90 if( sPeek( &stream ) == MAKE_CTAG( CTAG_RI_PWRI ) )
91 {
92 readConstructed( &stream, NULL, CTAG_RI_PWRI );
93 status = readShortInteger( &stream, &value );
94 if( cryptStatusError( status ) )
95 {
96 sMemDisconnect( &stream );
97 return( CRYPT_FORMAT_NONE );
98 }
99 sMemDisconnect( &stream );
100
101 return( ( value == PWRI_VERSION ) ? \
102 CRYPT_FORMAT_CRYPTLIB : CRYPT_FORMAT_NONE );
103 }
104
105 #ifdef USE_PGP
106 /* It's not ASN.1 data, check for PGP data */
107 status = pgpReadPacketHeader( &stream, NULL, &value, 30, 8192 );
108 if( cryptStatusOK( status ) && value > 30 && value < 8192 )
109 {
110 sMemDisconnect( &stream );
111 return( CRYPT_FORMAT_PGP );
112 }
113 #endif /* USE_PGP */
114
115 sMemDisconnect( &stream );
116
117 return( CRYPT_FORMAT_NONE );
118 }
119
120 /* Check the key wrap key being used to import/export a session key */
121
122 CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
checkWrapKey(IN_HANDLE int importKey,OUT_ALGO_Z CRYPT_ALGO_TYPE * cryptAlgo,const BOOLEAN isImport)123 static int checkWrapKey( IN_HANDLE int importKey,
124 OUT_ALGO_Z CRYPT_ALGO_TYPE *cryptAlgo,
125 const BOOLEAN isImport )
126 {
127 int localCryptAlgo, status;
128
129 assert( isWritePtr( cryptAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
130
131 REQUIRES( isHandleRangeValid( importKey ) );
132
133 /* Clear return value */
134 *cryptAlgo = CRYPT_ALGO_NONE;
135
136 /* Make sure that the context is valid and get the algorithm being
137 used */
138 status = krnlSendMessage( importKey, MESSAGE_GETATTRIBUTE,
139 &localCryptAlgo, CRYPT_CTXINFO_ALGO );
140 if( cryptStatusError( status ) )
141 return( status );
142 if( isPkcAlgo( localCryptAlgo ) )
143 {
144 /* The DLP algorithms have specialised data-formatting requirements
145 and can't normally be directly accessed via external messages,
146 and PKC operations in general may be restricted to internal access
147 only if they have certificates that restrict their use associated
148 with them. However if we're performing a high-level key import
149 (rather than a low-level raw context operation) this is OK since
150 the low-level operation is being performed via these higher-level
151 routines which handle the formatting requirements. Doing the
152 check via an internal message is safe at this point since we've
153 already checked the context's external accessibility when we got
154 the algorithm info */
155 status = krnlSendMessage( importKey, IMESSAGE_CHECK, NULL,
156 isImport ? MESSAGE_CHECK_PKC_DECRYPT : \
157 MESSAGE_CHECK_PKC_ENCRYPT );
158 }
159 else
160 {
161 status = krnlSendMessage( importKey, MESSAGE_CHECK, NULL,
162 MESSAGE_CHECK_CRYPT );
163 }
164 if( cryptStatusError( status ) )
165 return( status );
166
167 *cryptAlgo = localCryptAlgo;
168 return( CRYPT_OK );
169 }
170
171 /* Check that the context data is encodable using the chosen format */
172
173 CHECK_RETVAL \
checkContextsEncodable(IN_HANDLE const CRYPT_HANDLE exportKey,IN_ALGO const CRYPT_ALGO_TYPE exportAlgo,IN_HANDLE const CRYPT_CONTEXT sessionKeyContext,IN_ENUM (CRYPT_FORMAT)const CRYPT_FORMAT_TYPE formatType)174 static int checkContextsEncodable( IN_HANDLE const CRYPT_HANDLE exportKey,
175 IN_ALGO const CRYPT_ALGO_TYPE exportAlgo,
176 IN_HANDLE const CRYPT_CONTEXT sessionKeyContext,
177 IN_ENUM( CRYPT_FORMAT ) \
178 const CRYPT_FORMAT_TYPE formatType )
179 {
180 const BOOLEAN exportIsPKC = isPkcAlgo( exportAlgo ) ? TRUE : FALSE;
181 BOOLEAN sessionIsMAC = FALSE;
182 int sessionKeyAlgo, sessionKeyMode DUMMY_INIT, status;
183
184 REQUIRES( isHandleRangeValid( exportKey ) );
185 REQUIRES( exportAlgo > CRYPT_ALGO_NONE && exportAlgo < CRYPT_ALGO_LAST );
186 REQUIRES( isHandleRangeValid( sessionKeyContext ) );
187 REQUIRES( formatType > CRYPT_FORMAT_NONE && \
188 formatType < CRYPT_FORMAT_LAST_EXTERNAL );
189
190 /* Get any required context information */
191 status = krnlSendMessage( sessionKeyContext, MESSAGE_GETATTRIBUTE,
192 &sessionKeyAlgo, CRYPT_CTXINFO_ALGO );
193 if( cryptStatusError( status ) )
194 return( CRYPT_ERROR_PARAM3 );
195 if( isMacAlgo( sessionKeyAlgo ) )
196 sessionIsMAC = TRUE;
197 else
198 {
199 status = krnlSendMessage( sessionKeyContext, MESSAGE_GETATTRIBUTE,
200 &sessionKeyMode, CRYPT_CTXINFO_MODE );
201 if( cryptStatusError( status ) )
202 return( CRYPT_ERROR_PARAM3 );
203 }
204
205 switch( formatType )
206 {
207 case CRYPT_FORMAT_CRYPTLIB:
208 case CRYPT_FORMAT_CMS:
209 case CRYPT_FORMAT_SMIME:
210 /* Check that the export algorithm is encodable */
211 if( exportIsPKC )
212 {
213 if( cryptStatusError( sizeofAlgoID( exportAlgo ) ) )
214 return( CRYPT_ERROR_PARAM1 );
215 }
216 else
217 {
218 int exportMode; /* int vs.enum */
219
220 /* If it's a conventional key export, the key wrap mechanism
221 requires the use of CBC mode for the wrapping */
222 status = krnlSendMessage( exportKey, MESSAGE_GETATTRIBUTE,
223 &exportMode, CRYPT_CTXINFO_MODE );
224 if( cryptStatusError( status ) )
225 return( CRYPT_ERROR_PARAM1 );
226 if( exportMode != CRYPT_MODE_CBC || \
227 cryptStatusError( \
228 sizeofAlgoIDex( exportAlgo, exportMode, 0 ) ) )
229 return( CRYPT_ERROR_PARAM1 );
230 }
231
232 /* Check that the session-key algorithm is encodable */
233 if( sessionIsMAC )
234 status = sizeofAlgoID( sessionKeyAlgo );
235 else
236 status = checkAlgoID( sessionKeyAlgo, sessionKeyMode );
237 if( cryptStatusError( status ) )
238 return( CRYPT_ERROR_PARAM3 );
239
240 return( CRYPT_OK );
241
242 #ifdef USE_PGP
243 case CRYPT_FORMAT_PGP:
244 {
245 int dummy;
246
247 /* Check that the export algorithm is encodable */
248 if( cryptStatusError( \
249 cryptlibToPgpAlgo( exportAlgo, &dummy ) ) )
250 return( CRYPT_ERROR_PARAM1 );
251
252 /* Check that the session-key algorithm is encodable */
253 if( exportIsPKC )
254 {
255 if( cryptStatusError( \
256 cryptlibToPgpAlgo( sessionKeyAlgo, &dummy ) ) )
257 return( CRYPT_ERROR_PARAM3 );
258 if( sessionKeyMode != CRYPT_MODE_CFB )
259 return( CRYPT_ERROR_PARAM3 );
260 }
261 else
262 {
263 int exportMode; /* int vs.enum */
264
265 /* If it's a conventional key export there's no key wrap as
266 in CMS (the session-key context isn't used), so the
267 "export context" mode must be CFB */
268 status = krnlSendMessage( exportKey, MESSAGE_GETATTRIBUTE,
269 &exportMode, CRYPT_CTXINFO_MODE );
270 if( cryptStatusError( status ) || \
271 exportMode != CRYPT_MODE_CFB )
272 return( CRYPT_ERROR_PARAM1 );
273 }
274
275 return( CRYPT_OK );
276 }
277 #endif /* USE_PGP */
278 }
279
280 /* It's an invalid/unknown format, we can't check the encodability of
281 the context data */
282 return( CRYPT_ERROR_PARAM4 );
283 }
284
285 /****************************************************************************
286 * *
287 * Import a Session Key *
288 * *
289 ****************************************************************************/
290
291 /* Import an extended encrypted key, either a cryptlib key or a CMS key */
292
293 C_CHECK_RETVAL C_NONNULL_ARG( ( 1 ) ) \
cryptImportKeyEx(C_IN void C_PTR encryptedKey,C_IN int encryptedKeyLength,C_IN CRYPT_CONTEXT importKey,C_IN CRYPT_CONTEXT sessionKeyContext,C_OUT_OPT CRYPT_CONTEXT C_PTR returnedContext)294 C_RET cryptImportKeyEx( C_IN void C_PTR encryptedKey,
295 C_IN int encryptedKeyLength,
296 C_IN CRYPT_CONTEXT importKey,
297 C_IN CRYPT_CONTEXT sessionKeyContext,
298 C_OUT_OPT CRYPT_CONTEXT C_PTR returnedContext )
299 {
300 CRYPT_CONTEXT iReturnedContext DUMMY_INIT;
301 CRYPT_FORMAT_TYPE formatType;
302 CRYPT_ALGO_TYPE importAlgo;
303 int owner = CRYPT_ERROR, originalOwner = CRYPT_ERROR, status;
304
305 /* Perform basic error checking */
306 if( encryptedKeyLength <= MIN_CRYPT_OBJECTSIZE || \
307 encryptedKeyLength >= MAX_INTLENGTH_SHORT )
308 return( CRYPT_ERROR_PARAM2 );
309 if( !isReadPtr( encryptedKey, encryptedKeyLength ) )
310 return( CRYPT_ERROR_PARAM1 );
311 if( ( formatType = \
312 getFormatType( encryptedKey, encryptedKeyLength ) ) == CRYPT_FORMAT_NONE )
313 return( CRYPT_ERROR_BADDATA );
314 if( !isHandleRangeValid( importKey ) )
315 return( CRYPT_ERROR_PARAM3 );
316 if( sessionKeyContext != CRYPT_UNUSED && \
317 !isHandleRangeValid( sessionKeyContext ) )
318 return( CRYPT_ERROR_PARAM4 );
319
320 /* Check the importing key */
321 status = checkWrapKey( importKey, &importAlgo, TRUE );
322 if( cryptStatusError( status ) )
323 return( cryptArgError( status ) ? CRYPT_ERROR_PARAM3 : status );
324
325 /* Check the session key */
326 if( formatType == CRYPT_FORMAT_PGP )
327 {
328 /* PGP stores the session key information with the encrypted key
329 data, so the user can't provide a context */
330 if( sessionKeyContext != CRYPT_UNUSED )
331 return( CRYPT_ERROR_PARAM4 );
332 if( !isWritePtrConst( returnedContext, sizeof( CRYPT_CONTEXT ) ) )
333 return( CRYPT_ERROR_PARAM5 );
334 *returnedContext = CRYPT_ERROR;
335 }
336 else
337 {
338 int sessionKeyAlgo; /* int vs.enum */
339
340 if( !isHandleRangeValid( sessionKeyContext ) )
341 return( CRYPT_ERROR_PARAM4 );
342 status = krnlSendMessage( sessionKeyContext, MESSAGE_GETATTRIBUTE,
343 &sessionKeyAlgo, CRYPT_CTXINFO_ALGO );
344 if( cryptStatusOK( status ) )
345 {
346 status = krnlSendMessage( sessionKeyContext, MESSAGE_CHECK, NULL,
347 isMacAlgo( sessionKeyAlgo ) ? \
348 MESSAGE_CHECK_MAC_READY : \
349 MESSAGE_CHECK_CRYPT_READY );
350 }
351 if( cryptStatusError( status ) )
352 return( cryptArgError( status ) ? CRYPT_ERROR_PARAM4 : status );
353 if( returnedContext != NULL )
354 return( CRYPT_ERROR_PARAM5 );
355 }
356
357 /* If the importing key is owned, bind the session key context to the same
358 owner before we load a key into it. We also need to save the original
359 owner so that we can undo the binding later if things fail */
360 status = krnlSendMessage( importKey, MESSAGE_GETATTRIBUTE, &owner,
361 CRYPT_PROPERTY_OWNER );
362 if( cryptStatusOK( status ) && sessionKeyContext != CRYPT_UNUSED )
363 {
364 /* The importing key is owned, set the imported key's owner */
365 status = krnlSendMessage( sessionKeyContext, MESSAGE_GETATTRIBUTE,
366 &originalOwner, CRYPT_PROPERTY_OWNER );
367 if( cryptStatusOK( status ) )
368 {
369 status = krnlSendMessage( sessionKeyContext, MESSAGE_SETATTRIBUTE,
370 &owner, CRYPT_PROPERTY_OWNER );
371 if( cryptStatusError( status ) )
372 return( status );
373 }
374 else
375 {
376 /* Don't try and reset the session key ownership on error */
377 originalOwner = CRYPT_ERROR;
378 }
379 }
380
381 /* Import it as appropriate */
382 status = iCryptImportKey( encryptedKey, encryptedKeyLength, formatType,
383 importKey, sessionKeyContext,
384 ( formatType == CRYPT_FORMAT_PGP ) ? \
385 &iReturnedContext : NULL );
386 if( cryptStatusError( status ) )
387 {
388 /* The import failed, return the session key context to its
389 original owner. If this fails there's not much that we can do
390 to recover so we don't do anything with the return value */
391 if( originalOwner != CRYPT_ERROR )
392 {
393 ( void ) krnlSendMessage( sessionKeyContext,
394 MESSAGE_SETATTRIBUTE,
395 &originalOwner, CRYPT_PROPERTY_OWNER );
396 }
397 if( cryptArgError( status ) )
398 {
399 /* If we get an argument error from the lower-level code, map the
400 parameter number to the function argument number */
401 status = ( status == CRYPT_ARGERROR_NUM1 ) ? \
402 CRYPT_ERROR_PARAM4 : CRYPT_ERROR_PARAM3;
403 }
404 return( status );
405 }
406
407 #ifdef USE_PGP
408 /* If it's a PGP key import then the session key was recreated from
409 information stored with the wrapped key so we have to make it
410 externally visible before it can be used by the caller */
411 if( formatType == CRYPT_FORMAT_PGP && isPkcAlgo( importAlgo ) )
412 {
413 /* If the importing key is owned, set the imported key's owner */
414 if( owner != CRYPT_ERROR )
415 {
416 status = krnlSendMessage( iReturnedContext,
417 IMESSAGE_SETATTRIBUTE,
418 &owner, CRYPT_PROPERTY_OWNER );
419 if( cryptStatusError( status ) )
420 {
421 krnlSendNotifier( iReturnedContext, IMESSAGE_DECREFCOUNT );
422 return( status );
423 }
424 }
425
426 /* Make the newly-created context externally visible */
427 status = krnlSendMessage( iReturnedContext, IMESSAGE_SETATTRIBUTE,
428 MESSAGE_VALUE_FALSE,
429 CRYPT_IATTRIBUTE_INTERNAL );
430 if( cryptStatusError( status ) )
431 {
432 krnlSendNotifier( iReturnedContext, IMESSAGE_DECREFCOUNT );
433 return( status );
434 }
435 *returnedContext = iReturnedContext;
436 }
437 #endif /* USE_PGP */
438
439 return( CRYPT_OK );
440 }
441
442 C_CHECK_RETVAL C_NONNULL_ARG( ( 1 ) ) \
cryptImportKey(C_IN void C_PTR encryptedKey,C_IN int encryptedKeyLength,C_IN CRYPT_CONTEXT importKey,C_IN CRYPT_CONTEXT sessionKeyContext)443 C_RET cryptImportKey( C_IN void C_PTR encryptedKey,
444 C_IN int encryptedKeyLength,
445 C_IN CRYPT_CONTEXT importKey,
446 C_IN CRYPT_CONTEXT sessionKeyContext )
447 {
448 return( cryptImportKeyEx( encryptedKey, encryptedKeyLength, importKey,
449 sessionKeyContext, NULL ) );
450 }
451
452 /****************************************************************************
453 * *
454 * Export a Session Key *
455 * *
456 ****************************************************************************/
457
458 /* Export an extended encrypted key, either a cryptlib key or a CMS key */
459
460 C_CHECK_RETVAL C_NONNULL_ARG( ( 3 ) ) \
cryptExportKeyEx(C_OUT_OPT void C_PTR encryptedKey,C_IN int encryptedKeyMaxLength,C_OUT int C_PTR encryptedKeyLength,C_IN CRYPT_FORMAT_TYPE formatType,C_IN CRYPT_HANDLE exportKey,C_IN CRYPT_CONTEXT sessionKeyContext)461 C_RET cryptExportKeyEx( C_OUT_OPT void C_PTR encryptedKey,
462 C_IN int encryptedKeyMaxLength,
463 C_OUT int C_PTR encryptedKeyLength,
464 C_IN CRYPT_FORMAT_TYPE formatType,
465 C_IN CRYPT_HANDLE exportKey,
466 C_IN CRYPT_CONTEXT sessionKeyContext )
467 {
468 CRYPT_ALGO_TYPE exportAlgo;
469 int sessionKeyAlgo, status; /* int vs.enum */
470
471 /* Perform basic error checking */
472 if( encryptedKey != NULL )
473 {
474 if( encryptedKeyMaxLength <= MIN_CRYPT_OBJECTSIZE || \
475 encryptedKeyMaxLength >= MAX_BUFFER_SIZE )
476 return( CRYPT_ERROR_PARAM2 );
477 if( !isWritePtr( encryptedKey, encryptedKeyMaxLength ) )
478 return( CRYPT_ERROR_PARAM1 );
479 memset( encryptedKey, 0, MIN_CRYPT_OBJECTSIZE );
480 }
481 else
482 {
483 if( encryptedKeyMaxLength != 0 )
484 return( CRYPT_ERROR_PARAM2 );
485 }
486 if( !isWritePtrConst( encryptedKeyLength, sizeof( int ) ) )
487 return( CRYPT_ERROR_PARAM3 );
488 *encryptedKeyLength = 0;
489 if( formatType != CRYPT_FORMAT_CRYPTLIB && \
490 formatType != CRYPT_FORMAT_CMS && \
491 formatType != CRYPT_FORMAT_SMIME && \
492 formatType != CRYPT_FORMAT_PGP )
493 return( CRYPT_ERROR_PARAM4 );
494 if( !isHandleRangeValid( exportKey ) )
495 return( CRYPT_ERROR_PARAM5 );
496 if( !isHandleRangeValid( sessionKeyContext ) )
497 return( CRYPT_ERROR_PARAM6 );
498
499 /* Check the exporting key */
500 status = checkWrapKey( exportKey, &exportAlgo, FALSE );
501 if( cryptStatusError( status ) )
502 return( cryptArgError( status ) ? CRYPT_ERROR_PARAM5 : status );
503 status = checkContextsEncodable( exportKey, exportAlgo,
504 sessionKeyContext, formatType );
505 if( cryptStatusError( status ) )
506 {
507 return( ( status == CRYPT_ERROR_PARAM1 ) ? CRYPT_ERROR_PARAM5 : \
508 ( status == CRYPT_ERROR_PARAM3 ) ? CRYPT_ERROR_PARAM6 : \
509 CRYPT_ERROR_PARAM4 );
510 }
511
512 /* Check the exported key */
513 status = krnlSendMessage( sessionKeyContext, MESSAGE_GETATTRIBUTE,
514 &sessionKeyAlgo, CRYPT_CTXINFO_ALGO );
515 if( cryptStatusError( status ) )
516 return( CRYPT_ERROR_PARAM6 );
517 status = krnlSendMessage( sessionKeyContext, MESSAGE_CHECK, NULL,
518 isMacAlgo( sessionKeyAlgo ) ? \
519 MESSAGE_CHECK_MAC : MESSAGE_CHECK_CRYPT );
520 if( cryptStatusError( status ) )
521 return( cryptArgError( status ) ? CRYPT_ERROR_PARAM6 : status );
522
523 /* Export the key via the shared export function */
524 status = iCryptExportKey( encryptedKey, encryptedKeyMaxLength,
525 encryptedKeyLength, formatType,
526 sessionKeyContext, exportKey );
527 if( cryptArgError( status ) )
528 {
529 /* If we get an argument error from the lower-level code, map the
530 parameter number to the function argument number */
531 status = ( status == CRYPT_ARGERROR_NUM1 ) ? \
532 CRYPT_ERROR_PARAM6 : CRYPT_ERROR_PARAM5;
533 }
534 return( status );
535 }
536
537 C_CHECK_RETVAL C_NONNULL_ARG( ( 3 ) ) \
cryptExportKey(C_OUT_OPT void C_PTR encryptedKey,C_IN int encryptedKeyMaxLength,C_OUT int C_PTR encryptedKeyLength,C_IN CRYPT_HANDLE exportKey,C_IN CRYPT_CONTEXT sessionKeyContext)538 C_RET cryptExportKey( C_OUT_OPT void C_PTR encryptedKey,
539 C_IN int encryptedKeyMaxLength,
540 C_OUT int C_PTR encryptedKeyLength,
541 C_IN CRYPT_HANDLE exportKey,
542 C_IN CRYPT_CONTEXT sessionKeyContext )
543 {
544 int status;
545
546 status = cryptExportKeyEx( encryptedKey, encryptedKeyMaxLength,
547 encryptedKeyLength, CRYPT_FORMAT_CRYPTLIB,
548 exportKey, sessionKeyContext );
549 return( ( status == CRYPT_ERROR_PARAM5 ) ? CRYPT_ERROR_PARAM4 : \
550 ( status == CRYPT_ERROR_PARAM6 ) ? CRYPT_ERROR_PARAM5 : status );
551 }
552
553 /****************************************************************************
554 * *
555 * Internal Import/Export Functions *
556 * *
557 ****************************************************************************/
558
559 /* Internal versions of the above. These skip a lot of the explicit
560 checking done by the external versions (e.g. "Is this value really a
561 handle to a valid PKC context?") since they're only called by cryptlib
562 internal functions rather than being passed untrusted user data */
563
564 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
iCryptImportKey(IN_BUFFER (encryptedKeyLength)const void * encryptedKey,IN_LENGTH_SHORT const int encryptedKeyLength,IN_ENUM (CRYPT_FORMAT)const CRYPT_FORMAT_TYPE formatType,IN_HANDLE const CRYPT_CONTEXT iImportKey,IN_HANDLE_OPT const CRYPT_CONTEXT iSessionKeyContext,OUT_OPT_HANDLE_OPT CRYPT_CONTEXT * iReturnedContext)565 int iCryptImportKey( IN_BUFFER( encryptedKeyLength ) const void *encryptedKey,
566 IN_LENGTH_SHORT const int encryptedKeyLength,
567 IN_ENUM( CRYPT_FORMAT ) const CRYPT_FORMAT_TYPE formatType,
568 IN_HANDLE const CRYPT_CONTEXT iImportKey,
569 IN_HANDLE_OPT const CRYPT_CONTEXT iSessionKeyContext,
570 OUT_OPT_HANDLE_OPT CRYPT_CONTEXT *iReturnedContext )
571 {
572 const KEYEX_TYPE keyexType = \
573 ( formatType == CRYPT_FORMAT_AUTO || \
574 formatType == CRYPT_FORMAT_CRYPTLIB ) ? KEYEX_CRYPTLIB : \
575 ( formatType == CRYPT_FORMAT_PGP ) ? KEYEX_PGP : KEYEX_CMS;
576 int importAlgo, status; /* int vs.enum */
577
578 assert( isReadPtr( encryptedKey, encryptedKeyLength ) );
579 assert( ( formatType == CRYPT_FORMAT_PGP && \
580 isWritePtr( iReturnedContext, sizeof( CRYPT_CONTEXT ) ) ) || \
581 ( formatType != CRYPT_FORMAT_PGP && \
582 iReturnedContext == NULL ) );
583
584 REQUIRES( encryptedKeyLength > MIN_CRYPT_OBJECTSIZE && \
585 encryptedKeyLength < MAX_INTLENGTH_SHORT );
586 REQUIRES( formatType > CRYPT_FORMAT_NONE && \
587 formatType < CRYPT_FORMAT_LAST );
588 REQUIRES( isHandleRangeValid( iImportKey ) );
589 REQUIRES( ( formatType == CRYPT_FORMAT_PGP && \
590 iSessionKeyContext == CRYPT_UNUSED ) || \
591 ( formatType != CRYPT_FORMAT_PGP && \
592 isHandleRangeValid( iSessionKeyContext ) ) );
593 REQUIRES( ( formatType == CRYPT_FORMAT_PGP && \
594 iReturnedContext != NULL ) || \
595 ( formatType != CRYPT_FORMAT_PGP && \
596 iReturnedContext == NULL ) );
597
598 /* Clear return values */
599 if( iReturnedContext != NULL )
600 *iReturnedContext = CRYPT_ERROR;
601
602 /* Import it as appropriate. We don't handle key agreement at this
603 level since it's a protocol-specific mechanism used by SSH and SSL,
604 which are internal-only formats */
605 status = krnlSendMessage( iImportKey, IMESSAGE_GETATTRIBUTE, &importAlgo,
606 CRYPT_CTXINFO_ALGO );
607 if( cryptStatusError( status ) )
608 return( status );
609 if( isConvAlgo( importAlgo ) )
610 {
611 if( !isHandleRangeValid( iSessionKeyContext ) )
612 return( CRYPT_ARGERROR_NUM2 );
613 return( importConventionalKey( encryptedKey, encryptedKeyLength,
614 iSessionKeyContext, iImportKey,
615 keyexType ) );
616 }
617 return( importPublicKey( encryptedKey, encryptedKeyLength,
618 iSessionKeyContext, iImportKey,
619 iReturnedContext, keyexType ) );
620 }
621
622 CHECK_RETVAL STDC_NONNULL_ARG( ( 3 ) ) \
iCryptExportKey(OUT_BUFFER_OPT (encryptedKeyMaxLength,* encryptedKeyLength)void * encryptedKey,IN_DATALENGTH_Z const int encryptedKeyMaxLength,OUT_DATALENGTH_Z int * encryptedKeyLength,IN_ENUM (CRYPT_FORMAT)const CRYPT_FORMAT_TYPE formatType,IN_HANDLE_OPT const CRYPT_CONTEXT iSessionKeyContext,IN_HANDLE const CRYPT_CONTEXT iExportKey)623 int iCryptExportKey( OUT_BUFFER_OPT( encryptedKeyMaxLength, *encryptedKeyLength ) \
624 void *encryptedKey,
625 IN_DATALENGTH_Z const int encryptedKeyMaxLength,
626 OUT_DATALENGTH_Z int *encryptedKeyLength,
627 IN_ENUM( CRYPT_FORMAT ) const CRYPT_FORMAT_TYPE formatType,
628 IN_HANDLE_OPT const CRYPT_CONTEXT iSessionKeyContext,
629 IN_HANDLE const CRYPT_CONTEXT iExportKey )
630 {
631 const KEYEX_TYPE keyexType = \
632 ( formatType == CRYPT_FORMAT_CRYPTLIB ) ? KEYEX_CRYPTLIB : \
633 ( formatType == CRYPT_FORMAT_PGP ) ? KEYEX_PGP : KEYEX_CMS;
634 DYNBUF auxDB;
635 const int encKeyMaxLength = ( encryptedKey == NULL ) ? \
636 0 : encryptedKeyMaxLength;
637 int exportAlgo, status; /* int vs.enum */
638
639 assert( ( encryptedKey == NULL && encryptedKeyMaxLength == 0 ) || \
640 ( encryptedKeyMaxLength >= MIN_CRYPT_OBJECTSIZE && \
641 isWritePtr( encryptedKey, encryptedKeyMaxLength ) ) );
642 assert( isWritePtr( encryptedKeyLength, sizeof( int ) ) );
643
644 REQUIRES( ( encryptedKey == NULL && encryptedKeyMaxLength == 0 ) || \
645 ( encryptedKeyMaxLength > MIN_CRYPT_OBJECTSIZE && \
646 encryptedKeyMaxLength < MAX_BUFFER_SIZE ) );
647 REQUIRES( formatType > CRYPT_FORMAT_NONE && \
648 formatType < CRYPT_FORMAT_LAST );
649 REQUIRES( ( formatType == CRYPT_FORMAT_PGP && \
650 iSessionKeyContext == CRYPT_UNUSED ) || \
651 isHandleRangeValid( iSessionKeyContext ) );
652 REQUIRES( isHandleRangeValid( iExportKey ) );
653
654 ANALYSER_HINT( encryptedKeyLength != NULL );
655
656 /* Clear return value */
657 *encryptedKeyLength = 0;
658
659 /* Perform simplified error checking */
660 status = krnlSendMessage( iExportKey, IMESSAGE_GETATTRIBUTE, &exportAlgo,
661 CRYPT_CTXINFO_ALGO );
662 if( cryptStatusError( status ) )
663 return( cryptArgError( status ) ? CRYPT_ARGERROR_NUM2 : status );
664
665 /* If it's a non-PKC export, pass the call down to the low-level export
666 function */
667 if( !isPkcAlgo( exportAlgo ) )
668 {
669 return( exportConventionalKey( encryptedKey, encKeyMaxLength,
670 encryptedKeyLength, iSessionKeyContext,
671 iExportKey, keyexType ) );
672 }
673
674 REQUIRES( isHandleRangeValid( iSessionKeyContext ) );
675
676 /* If it's a non-CMS/SMIME PKC export, pass the call down to the low-
677 level export function */
678 if( formatType != CRYPT_FORMAT_CMS && formatType != CRYPT_FORMAT_SMIME )
679 {
680 return( exportPublicKey( encryptedKey, encKeyMaxLength,
681 encryptedKeyLength, iSessionKeyContext,
682 iExportKey, NULL, 0, keyexType ) );
683 }
684
685 /* We're exporting a key in CMS format we need to obtain recipient
686 information from the certificate associated with the export context.
687 First we lock the certificate for our exclusive use and in case it's
688 a certificate chain select the first certificate in the chain */
689 status = krnlSendMessage( iExportKey, IMESSAGE_SETATTRIBUTE,
690 MESSAGE_VALUE_TRUE, CRYPT_IATTRIBUTE_LOCKED );
691 if( cryptStatusError( status ) )
692 return( CRYPT_ERROR_PARAM5 );
693 status = krnlSendMessage( iExportKey, IMESSAGE_SETATTRIBUTE,
694 MESSAGE_VALUE_CURSORFIRST,
695 CRYPT_CERTINFO_CURRENT_CERTIFICATE );
696 if( cryptStatusError( status ) )
697 {
698 /* Unlock the chain before we exit. If this fails there's not much
699 that we can do to recover so we don't do anything with the return
700 value */
701 ( void ) krnlSendMessage( iExportKey, IMESSAGE_SETATTRIBUTE,
702 MESSAGE_VALUE_FALSE,
703 CRYPT_IATTRIBUTE_LOCKED );
704 return( CRYPT_ERROR_PARAM5 );
705 }
706
707 /* Next we get the recipient information from the certificate into a
708 dynbuf */
709 status = dynCreate( &auxDB, iExportKey,
710 CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
711 if( cryptStatusError( status ) )
712 {
713 ( void ) krnlSendMessage( iExportKey, IMESSAGE_SETATTRIBUTE,
714 MESSAGE_VALUE_FALSE,
715 CRYPT_IATTRIBUTE_LOCKED );
716 return( CRYPT_ERROR_PARAM5 );
717 }
718
719 /* We're ready to export the key alongside the key ID as auxiliary
720 data */
721 status = exportPublicKey( encryptedKey, encKeyMaxLength,
722 encryptedKeyLength, iSessionKeyContext,
723 iExportKey, dynData( auxDB ),
724 dynLength( auxDB ), keyexType );
725
726 /* Clean up. If the unlock fails there's not much that we can do to
727 recover so we don't do anything with the return value */
728 ( void ) krnlSendMessage( iExportKey, IMESSAGE_SETATTRIBUTE,
729 MESSAGE_VALUE_FALSE, CRYPT_IATTRIBUTE_LOCKED );
730 dynDestroy( &auxDB );
731
732 return( status );
733 }
734
735 #else
736
737 /****************************************************************************
738 * *
739 * Stub Functions for non-CMS/PGP Use *
740 * *
741 ****************************************************************************/
742
cryptImportKeyEx(C_IN void C_PTR encryptedKey,C_IN int encryptedKeyLength,C_IN CRYPT_CONTEXT importKey,C_IN CRYPT_CONTEXT sessionKeyContext,C_OUT CRYPT_CONTEXT C_PTR returnedContext)743 C_RET cryptImportKeyEx( C_IN void C_PTR encryptedKey,
744 C_IN int encryptedKeyLength,
745 C_IN CRYPT_CONTEXT importKey,
746 C_IN CRYPT_CONTEXT sessionKeyContext,
747 C_OUT CRYPT_CONTEXT C_PTR returnedContext )
748 {
749 UNUSED_ARG( encryptedKey );
750 UNUSED_ARG( returnedContext );
751
752 return( CRYPT_ERROR_NOTAVAIL );
753 }
754
cryptImportKey(C_IN void C_PTR encryptedKey,C_IN int encryptedKeyLength,C_IN CRYPT_CONTEXT importKey,C_IN CRYPT_CONTEXT sessionKeyContext)755 C_RET cryptImportKey( C_IN void C_PTR encryptedKey,
756 C_IN int encryptedKeyLength,
757 C_IN CRYPT_CONTEXT importKey,
758 C_IN CRYPT_CONTEXT sessionKeyContext )
759 {
760 UNUSED_ARG( encryptedKey );
761
762 return( CRYPT_ERROR_NOTAVAIL );
763 }
764
cryptExportKeyEx(C_OUT_OPT void C_PTR encryptedKey,C_IN int encryptedKeyMaxLength,C_OUT int C_PTR encryptedKeyLength,C_IN CRYPT_FORMAT_TYPE formatType,C_IN CRYPT_HANDLE exportKey,C_IN CRYPT_CONTEXT sessionKeyContext)765 C_RET cryptExportKeyEx( C_OUT_OPT void C_PTR encryptedKey,
766 C_IN int encryptedKeyMaxLength,
767 C_OUT int C_PTR encryptedKeyLength,
768 C_IN CRYPT_FORMAT_TYPE formatType,
769 C_IN CRYPT_HANDLE exportKey,
770 C_IN CRYPT_CONTEXT sessionKeyContext )
771 {
772 UNUSED_ARG( encryptedKey );
773 UNUSED_ARG( encryptedKeyLength );
774
775 return( CRYPT_ERROR_NOTAVAIL );
776 }
777
cryptExportKey(C_OUT_OPT void C_PTR encryptedKey,C_IN int encryptedKeyMaxLength,C_OUT int C_PTR encryptedKeyLength,C_IN CRYPT_HANDLE exportKey,C_IN CRYPT_CONTEXT sessionKeyContext)778 C_RET cryptExportKey( C_OUT_OPT void C_PTR encryptedKey,
779 C_IN int encryptedKeyMaxLength,
780 C_OUT int C_PTR encryptedKeyLength,
781 C_IN CRYPT_HANDLE exportKey,
782 C_IN CRYPT_CONTEXT sessionKeyContext )
783 {
784 UNUSED_ARG( encryptedKey );
785 UNUSED_ARG( encryptedKeyLength );
786
787 return( CRYPT_ERROR_NOTAVAIL );
788 }
789 #endif /* USE_INT_CMS */
790