cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
obj_acc.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Object Alternative Access *
4 * Copyright Peter Gutmann 1997-2005 *
5 * *
6 ****************************************************************************/
7 
8 /* Sending a message to an object only makes the one object which is the
9  target of the message available for use. When we need simultaneous
10  access to two objects (for example when copying a collection of cert
11  extensions from one cert to another), we have to use the
12  krnlAcquireObject()/krnlReleaseObject() functions to obtain access to
13  the second object's internals.
14 
15  There is a second situation in which we need access to an object's
16  internals, and that occurs when we need to export/import a key from/to
17  a context. This is handled via the key extract functions at the end
18  of this module, see the comments there for further information */
19 
20 #if defined( INC_ALL )
21  #include "crypt.h"
22  #include "acl.h"
23  #include "kernel.h"
24 #else
25  #include "crypt.h"
26  #include "kernel/acl.h"
27  #include "kernel/kernel.h"
28 #endif /* Compiler-specific includes */
29 
30 /* A pointer to the kernel data block */
31 
32 static KERNEL_DATA *krnlData = NULL;
33 
34 /* Optionally include the Intel Thread Checker API to control analysis of
35  the object mutexes */
36 
37 #if defined( _MSC_VER ) && ( _MSC_VER == 1200 ) && 0
38  #include "../../../Intel/VTune/tcheck/Include/libittnotify.h"
39  #pragma comment( lib, "C:/Program Files/Intel/VTune/Analyzer/Lib/libittnotify.lib" )
40 
41  #define THREAD_NOTIFY_PREPARE( id ) __itt_notify_sync_prepare( ( void * ) id );
42  #define THREAD_NOTIFY_CANCELLED( id ) __itt_notify_sync_prepare( ( void * ) id );
43  #define THREAD_NOTIFY_ACQUIRED( id ) __itt_notify_sync_acquired( ( void * ) id );
44  #define THREAD_NOTIFY_RELEASED( id ) __itt_notify_sync_releasing( ( void * ) id );
45 #else
46  #define THREAD_NOTIFY_PREPARE( dummy )
47  #define THREAD_NOTIFY_CANCELLED( dummy )
48  #define THREAD_NOTIFY_ACQUIRED( dummy )
49  #define THREAD_NOTIFY_RELEASED( dummy )
50 #endif /* VC++ 6.0 with Intel Thread Checker */
51 
52 /****************************************************************************
53 * *
54 * Utility Functions *
55 * *
56 ****************************************************************************/
57 
58 /* The type of checking that we perform for the object access. The check
59  types are:
60 
61  CHECK_EXTACCESS
62  Kernel-external call with a cert or crypto device to allow access to
63  object-internal data.
64 
65  CHECK_KEYACCESS
66  Kernel-internal call with a context for key export/import.
67 
68  CHECK_SUSPEND
69  Kernel-external call with a user or system object to temporarily
70  suspend object use and allow others access, providing a (somewhat
71  crude) mechanism for making kernel calls interruptible */
72 
73 typedef enum {
74  ACCESS_CHECK_NONE, /* No access check type */
75  ACCESS_CHECK_EXTACCESS, /* Generic external call: Cert or crypt.dev.*/
76  ACCESS_CHECK_KEYACCESS, /* Internal call: Context for key export */
77  ACCESS_CHECK_SUSPEND, /* Suspend object use: User or sys.obj.*/
78  ACCESS_CHECK_LAST /* Last access check type */
80 
81 /* Check that this is an object for which direct access is valid. We can
82  only access the following object types:
83 
84  Certificates: EXTACCESS, used when copying internal state such as cert
85  extensions or CRL info from one cert object to another.
86 
87  Contexts: KEYACCESS, used when importing/exporting keys to/from contexts
88  during key wrap/unwrap operations.
89 
90  Crypto hardware devices other than the system object: EXTACCESS, used
91  when a context tied to a device needs to perform an operation using
92  the device.
93 
94  System object: ACCESS_CHECK_SUSPEND, used when performing a randomness
95  data read/write, which can take some time to complete.
96 
97  User objects: ACCESS_CHECK_SUSPEND, used when committing config data to
98  persistent storage. We don't actually use the object data but
99  merely unlock it to allow others access while performing the
100  potentially lengthy update. Also used when performing the self-
101  test */
102 
103 CHECK_RETVAL \
104 static int checkAccessValid( IN_HANDLE const int objectHandle,
105  IN_ENUM( ACCESS_CHECK ) \
106  const ACCESS_CHECK_TYPE checkType,
107  IN_ERROR const int errorCode )
108  {
109  OBJECT_INFO *objectTable = krnlData->objectTable, *objectInfoPtr;
110 
111  REQUIRES( isValidObject( objectHandle ) );
112  REQUIRES( checkType > ACCESS_CHECK_NONE && \
113  checkType < ACCESS_CHECK_LAST );
114  REQUIRES( cryptStatusError( errorCode ) );
115 
116  /* Perform similar access checks to the ones performed in
117  krnlSendMessage(): It's a valid object owned by the calling
118  thread */
119  if( !isValidObject( objectHandle ) || \
120  !checkObjectOwnership( objectTable[ objectHandle ] ) )
121  return( errorCode );
122 
123  /* It's a valid object, get its info */
124  objectInfoPtr = &objectTable[ objectHandle ];
125 
126  /* Make sure that the object access is valid */
127  switch( objectInfoPtr->type )
128  {
129  case OBJECT_TYPE_CONTEXT:
130  /* Used when exporting/importing keying info, valid for contexts
131  with keys when called from within the kernel */
132  if( checkType != ACCESS_CHECK_KEYACCESS )
133  return( errorCode );
134  if( !isValidSubtype( objectInfoPtr->subType, SUBTYPE_CTX_CONV ) && \
135  !isValidSubtype( objectInfoPtr->subType, SUBTYPE_CTX_MAC ) && \
136  !isValidSubtype( objectInfoPtr->subType, SUBTYPE_CTX_PKC ) && \
137  !isValidSubtype( objectInfoPtr->subType, SUBTYPE_CTX_GENERIC ) )
138  return( errorCode );
139  break;
140 
142  /* Used when copying internal state such as cert extensions or
143  CRL info from one cert object to another. This is valid for
144  all cert types */
145  if( checkType != ACCESS_CHECK_EXTACCESS )
146  return( errorCode );
147  break;
148 
149  case OBJECT_TYPE_DEVICE:
150  /* If it's an external access operation, it's used when a
151  context tied to a crypto hardware device needs to perform an
152  operation using the device. This is valid for all devices
153  other than the system object */
154  if( checkType == ACCESS_CHECK_EXTACCESS )
155  {
156  if( !isValidSubtype( objectInfoPtr->subType, SUBTYPE_DEV_PKCS11 ) && \
157  !isValidSubtype( objectInfoPtr->subType, SUBTYPE_DEV_CRYPTOAPI ) && \
158  !isValidSubtype( objectInfoPtr->subType, SUBTYPE_DEV_HARDWARE ) )
159  return( errorCode );
160  }
161  else
162  {
163  /* If it's a suspend operation, it's used to temporarily
164  allow access to the system object while other operations
165  are being performed */
166  if( checkType != ACCESS_CHECK_SUSPEND )
167  return( errorCode );
168  if( !isValidSubtype( objectInfoPtr->subType, SUBTYPE_DEV_SYSTEM ) )
169  return( errorCode );
170  }
171  break;
172 
173  case OBJECT_TYPE_USER:
174  /* Used when updating config data, which can take awhile. The
175  default user is an SO user, which is why we check for this
176  user type */
177  if( checkType != ACCESS_CHECK_SUSPEND )
178  return( errorCode );
179  if( !isValidSubtype( objectInfoPtr->subType, SUBTYPE_USER_SO ) )
180  return( errorCode );
181  break;
182 
183  default:
184  retIntError();
185  }
186 
187  /* Postcondition: The object is of the appropriate type for the access */
188  ENSURES( ( checkType == ACCESS_CHECK_EXTACCESS && \
189  ( objectInfoPtr->type == OBJECT_TYPE_CERTIFICATE || \
190  objectInfoPtr->type == OBJECT_TYPE_DEVICE ) ) || \
191  ( checkType == ACCESS_CHECK_KEYACCESS && \
192  objectInfoPtr->type == OBJECT_TYPE_CONTEXT ) || \
193  ( checkType == ACCESS_CHECK_SUSPEND && \
194  ( objectInfoPtr->type == OBJECT_TYPE_DEVICE || \
195  objectInfoPtr->type == OBJECT_TYPE_USER ) ) );
196 
197  return( CRYPT_OK );
198  }
199 
200 /* Get a pointer to an object's data from its handle */
201 
202 CHECK_RETVAL \
203 static int getObject( IN_HANDLE const int objectHandle,
204  IN_ENUM( OBJECT ) const OBJECT_TYPE type,
205  IN_ENUM( ACCESS_CHECK ) const ACCESS_CHECK_TYPE checkType,
206  OUT_OPT_PTR_OPT void **objectPtr,
207  IN_INT_Z const int refCount,
208  IN_ERROR const int errorCode )
209  {
210  OBJECT_INFO *objectTable, *objectInfoPtr;
211  int status;
212 
213  assert( ( ( objectHandle == SYSTEM_OBJECT_HANDLE || \
214  objectHandle == DEFAULTUSER_OBJECT_HANDLE ) && \
215  objectPtr == NULL && refCount > 0 ) || \
216  ( !( objectHandle == SYSTEM_OBJECT_HANDLE || \
217  objectHandle == DEFAULTUSER_OBJECT_HANDLE ) && \
218  isWritePtr( objectPtr, sizeof( void * ) ) && \
219  refCount == CRYPT_UNUSED ) );
220 
221  /* Preconditions: It's a valid object */
222  REQUIRES( isValidHandle( objectHandle ) );
223  REQUIRES( isValidType( type ) && \
224  ( type == OBJECT_TYPE_CONTEXT || \
225  type == OBJECT_TYPE_CERTIFICATE || \
226  type == OBJECT_TYPE_DEVICE || type == OBJECT_TYPE_USER ) );
227  REQUIRES( checkType > ACCESS_CHECK_NONE && \
228  checkType < ACCESS_CHECK_LAST );
229  REQUIRES( ( ( objectHandle == SYSTEM_OBJECT_HANDLE || \
230  objectHandle == DEFAULTUSER_OBJECT_HANDLE ) && \
231  objectPtr == NULL && refCount > 0 ) || \
232  ( !( objectHandle == SYSTEM_OBJECT_HANDLE || \
233  objectHandle == DEFAULTUSER_OBJECT_HANDLE ) && \
234  objectPtr != NULL && refCount == CRYPT_UNUSED ) );
235 
236  /* Clear the return value */
237  if( objectPtr != NULL )
238  *objectPtr = NULL;
239 
240  THREAD_NOTIFY_PREPARE( objectHandle );
241  MUTEX_LOCK( objectTable );
242  objectTable = krnlData->objectTable;
243 
244  /* Perform similar access checks to the ones performed in
245  krnlSendMessage(), as well as situation-specific additional checks
246  for correct object types */
247  status = checkAccessValid( objectHandle, checkType, errorCode );
248  if( cryptStatusError( status ) )
249  {
250  MUTEX_UNLOCK( objectTable );
251  THREAD_NOTIFY_CANCELLED( objectHandle );
252  retIntError_Ext( status );
253  }
254 
255  /* Perform additional checks for correct object types */
256  if( ( ( objectHandle == SYSTEM_OBJECT_HANDLE || \
257  objectHandle == DEFAULTUSER_OBJECT_HANDLE ) && \
258  objectPtr != NULL ) || \
259  objectTable[ objectHandle ].type != type )
260  {
261  MUTEX_UNLOCK( objectTable );
262  THREAD_NOTIFY_CANCELLED( objectHandle );
263  retIntError_Ext( errorCode );
264  }
265 
266  /* It's a valid object, get its info */
267  objectInfoPtr = &objectTable[ objectHandle ];
268 
269  /* Inner precondition: The object is of the requested type */
270  REQUIRES( objectInfoPtr->type == type && \
271  ( objectInfoPtr->type == OBJECT_TYPE_CONTEXT || \
272  objectInfoPtr->type == OBJECT_TYPE_CERTIFICATE || \
273  objectInfoPtr->type == OBJECT_TYPE_DEVICE || \
274  objectInfoPtr->type == OBJECT_TYPE_USER ) );
275 
276  /* If the object is busy, wait for it to become available */
277  if( isInUse( objectHandle ) && !isObjectOwner( objectHandle ) )
278  status = waitForObject( objectHandle, &objectInfoPtr );
279  if( cryptStatusError( status ) )
280  {
281  MUTEX_UNLOCK( objectTable );
282  THREAD_NOTIFY_CANCELLED( objectHandle );
283  return( status );
284  }
285 
286  /* If it's an external access to certificate/device info or an internal
287  access to access the object's keying data, increment the object's
288  reference count to reserve it for our exclusive use */
289  if( checkType == ACCESS_CHECK_EXTACCESS || \
290  checkType == ACCESS_CHECK_KEYACCESS )
291  objectInfoPtr->lockCount++;
292  else
293  {
294  /* If we're resuming use of an object that we suspended to allow
295  others access, reset the reference count */
296  REQUIRES( checkType == ACCESS_CHECK_SUSPEND );
297  REQUIRES( objectInfoPtr->lockCount == 0 );
298  REQUIRES( refCount > 0 && refCount < 100 );
299 
300  objectInfoPtr->lockCount = refCount;
301  }
302 #ifdef USE_THREADS
303  objectInfoPtr->lockOwner = THREAD_SELF();
304 #endif /* USE_THREADS */
305  if( objectPtr != NULL )
306  *objectPtr = objectInfoPtr->objectPtr;
307 
308  MUTEX_UNLOCK( objectTable );
309  THREAD_NOTIFY_ACQUIRED( objectHandle );
310  return( status );
311  }
312 
313 /* Release an object that we previously acquired directly. We don't require
314  that the return value of this function be checked by the caller since the
315  only time that we can get an error is if it's a 'can't-occur' internal
316  error and it's not obvious what they should do in that case (omnia iam
317  fient fieri quae posse negabam) */
318 
319 static int releaseObject( IN_HANDLE const int objectHandle,
320  IN_ENUM( ACCESS_CHECK ) const ACCESS_CHECK_TYPE checkType,
321  OUT_OPT_INT_Z int *refCount )
322  {
323  OBJECT_INFO *objectTable, *objectInfoPtr;
324  int status;
325  DECLARE_ORIGINAL_INT( lockCount );
326 
327  assert( ( ( checkType == ACCESS_CHECK_EXTACCESS || \
328  checkType == ACCESS_CHECK_KEYACCESS ) && \
329  refCount == NULL ) || \
330  ( checkType == ACCESS_CHECK_SUSPEND && \
331  isWritePtr( refCount, sizeof( int ) ) ) );
332 
333  /* Preconditions */
334  REQUIRES( checkType > ACCESS_CHECK_NONE && \
335  checkType < ACCESS_CHECK_LAST );
336  REQUIRES( ( ( checkType == ACCESS_CHECK_EXTACCESS || \
337  checkType == ACCESS_CHECK_KEYACCESS ) && \
338  refCount == NULL ) || \
339  ( checkType == ACCESS_CHECK_SUSPEND && \
340  refCount != NULL ) );
341 
342  THREAD_NOTIFY_PREPARE( objectHandle );
343  MUTEX_LOCK( objectTable );
344  objectTable = krnlData->objectTable;
345 
346  /* Preconditions: It's a valid object in use by the caller. Since these
347  checks require access to the object table we can only perform them
348  after we've locked it */
349  REQUIRES( isValidObject( objectHandle ) );
350  REQUIRES( isInUse( objectHandle ) && isObjectOwner( objectHandle ) );
351 
352  /* Perform similar access checks to the ones performed in
353  krnlSendMessage(), as well as situation-specific additional checks
354  for correct object types */
355  status = checkAccessValid( objectHandle, checkType,
357  if( cryptStatusError( status ) )
358  {
359  MUTEX_UNLOCK( objectTable );
360  THREAD_NOTIFY_CANCELLED( objectHandle );
361  retIntError_Ext( status );
362  }
363 
364  /* Perform additional checks for correct object types. The ownership
365  check in checkAccessValid() simply checks whether the current thread
366  is the overall object owner, isObjectOwner() checks whether the
367  current thread owns the lock on the object */
368  if( !isInUse( objectHandle ) || !isObjectOwner( objectHandle ) )
369  {
370  MUTEX_UNLOCK( objectTable );
371  THREAD_NOTIFY_CANCELLED( objectHandle );
373  }
374 
375  /* It's a valid object, get its info */
376  objectInfoPtr = &objectTable[ objectHandle ];
377 
378  /* If it was an external access to certificate/device info or an
379  internal access to the object's keying data, decrement the object's
380  reference count to allow others access again */
381  if( checkType == ACCESS_CHECK_EXTACCESS || \
382  checkType == ACCESS_CHECK_KEYACCESS )
383  {
384  STORE_ORIGINAL_INT( lockCount, objectInfoPtr->lockCount );
385 
386  objectInfoPtr->lockCount--;
387 
388  /* Postcondition: The object's lock count has been decremented and
389  is non-negative */
390  ENSURES( objectInfoPtr->lockCount == \
391  ORIGINAL_VALUE( lockCount ) - 1 );
392  ENSURES( objectInfoPtr->lockCount >= 0 && \
393  objectInfoPtr->lockCount < MAX_INTLENGTH );
394  }
395  else
396  {
397  /* It's an external access to free the object for access by others,
398  clear the reference count */
399  REQUIRES( checkType == ACCESS_CHECK_SUSPEND );
400 
401  *refCount = objectInfoPtr->lockCount;
402  objectInfoPtr->lockCount = 0;
403 
404  /* Postcondition: The object has been completely released */
405  ENSURES( !isInUse( objectHandle ) );
406  }
407 
408  MUTEX_UNLOCK( objectTable );
409  THREAD_NOTIFY_RELEASED( objectHandle );
410  return( CRYPT_OK );
411  }
412 
413 /****************************************************************************
414 * *
415 * Init/Shutdown Functions *
416 * *
417 ****************************************************************************/
418 
420 int initObjectAltAccess( INOUT KERNEL_DATA *krnlDataPtr )
421  {
422  assert( isWritePtr( krnlDataPtr, sizeof( KERNEL_DATA ) ) );
423 
424  /* Set up the reference to the kernel data block */
425  krnlData = krnlDataPtr;
426 
427  return( CRYPT_OK );
428  }
429 
430 void endObjectAltAccess( void )
431  {
432  krnlData = NULL;
433  }
434 
435 /****************************************************************************
436 * *
437 * Direct Object Access Functions *
438 * *
439 ****************************************************************************/
440 
441 /* Acquire/release an object */
442 
444 int krnlAcquireObject( IN_HANDLE const int objectHandle,
445  IN_ENUM( OBJECT ) const OBJECT_TYPE type,
446  OUT_OPT_PTR void **objectPtr,
447  IN_ERROR const int errorCode )
448  {
449  REQUIRES( objectPtr != NULL ); /* getObject() allows it to be NULL */
450 
451  return( getObject( objectHandle, type, ACCESS_CHECK_EXTACCESS,
452  objectPtr, CRYPT_UNUSED, errorCode ) );
453  }
454 
455 int krnlReleaseObject( IN_HANDLE const int objectHandle )
456  {
457  return( releaseObject( objectHandle, ACCESS_CHECK_EXTACCESS, NULL ) );
458  }
459 
460 /* Temporarily suspend use of an object to allow other threads access, and
461  resume object use afterwards. Note that PREfast will erroneously report
462  'attributes inconsistent with previous declaration' for these two
463  functions */
464 
466 int krnlSuspendObject( IN_HANDLE const int objectHandle,
467  OUT_INT_Z int *refCount )
468  {
469  return( releaseObject( objectHandle, ACCESS_CHECK_SUSPEND, refCount ) );
470  }
471 
472 CHECK_RETVAL \
473 int krnlResumeObject( IN_HANDLE const int objectHandle,
474  IN_INT_Z const int refCount )
475  {
476  return( getObject( objectHandle,
477  ( objectHandle == SYSTEM_OBJECT_HANDLE ) ? \
479  ACCESS_CHECK_SUSPEND, NULL, refCount,
480  CRYPT_ERROR_FAILED ) );
481  }
482 
483 /****************************************************************************
484 * *
485 * Key Extract Functions *
486 * *
487 ****************************************************************************/
488 
489 /* The cryptlib equivalent of trusted downgraders in other security models:
490  Functions that extract a key from a context. These functions need to
491  bypass the kernel's security checking in order to allow key export and
492  are the only ones that can do this. This is an unavoidable requirement
493  in the complete-isolation model - some bypass mechanism needs to be
494  present in order to allow a key to be exported from an encryption action
495  object. The three functions that perform the necessary operations are:
496 
497  extractKeyData: Extract a session key from a conventional/MAC/generic-
498  secret context prior to encryption with a KEK.
499  exportPrivateKey: Write private key data to a stream prior to encryption
500  with a KEK.
501  importPrivateKey: Read private key data from a stream after decryption
502  with a KEK. We use this rather than a generic
503  external private key load to avoid having the key
504  marked as an untrusted user-set key, and also because
505  it's easier to read the key data directly into the
506  context's bignum storage rather than adding indirection
507  via a CRYPT_PKCINFO_xxx structure */
508 
509 #define PKC_CONTEXT /* Indicate that we're working with PKC context */
510 #if defined( INC_ALL )
511  #include "context.h"
512  #include "mech_int.h"
513 #else
514  #include "context/context.h"
515  #include "mechs/mech_int.h"
516 #endif /* Compiler-specific includes */
517 
519 int extractKeyData( IN_HANDLE const CRYPT_CONTEXT iCryptContext,
522  IN_BUFFER( accessKeyLen ) const char *accessKey,
523  IN_LENGTH_FIXED( 7 ) const int accessKeyLen )
524  {
526  int status;
527 
528  assert( isWritePtr( keyData, keyDataLen ) );
529  assert( isReadPtr( accessKey, accessKeyLen ) );
530 
531  REQUIRES( isHandleRangeValid( iCryptContext ) );
532  REQUIRES( keyDataLen >= MIN_KEYSIZE && keyDataLen < MAX_INTLENGTH_SHORT );
533  REQUIRES( accessKeyLen == 7 );
534 
535  /* Clear return values */
536  memset( keyData, 0, keyDataLen );
537 
538  /* Make sure that we really intended to call this function */
539  ENSURES( accessKeyLen == 7 && !memcmp( accessKey, "keydata", 7 ) );
540 
541  /* Make sure that we've been given a conventional encryption, MAC, or
542  generic-secret context with a key loaded. This has already been
543  checked at a higher level, but we perform a sanity check here to be
544  safe */
545  status = getObject( iCryptContext, OBJECT_TYPE_CONTEXT,
547  ( void ** ) &contextInfoPtr, CRYPT_UNUSED,
549  if( cryptStatusError( status ) )
550  return( status );
551  if( ( contextInfoPtr->type != CONTEXT_CONV && \
552  contextInfoPtr->type != CONTEXT_MAC && \
553  contextInfoPtr->type != CONTEXT_GENERIC ) || \
554  !( contextInfoPtr->flags & CONTEXT_FLAG_KEY_SET ) )
555  {
556  releaseObject( iCryptContext, ACCESS_CHECK_KEYACCESS, NULL );
557  return( CRYPT_ARGERROR_OBJECT );
558  }
559 
560  /* Export the key data from the context */
561  switch( contextInfoPtr->type )
562  {
563  case CONTEXT_CONV:
564  if( contextInfoPtr->ctxConv->userKeyLength < MIN_KEYSIZE || \
565  contextInfoPtr->ctxConv->userKeyLength > keyDataLen )
566  {
567  DEBUG_DIAG(( "Key data is too long to export" ));
568  assert( DEBUG_WARN );
569  status = CRYPT_ERROR_OVERFLOW;
570  }
571  else
572  {
573  memcpy( keyData, contextInfoPtr->ctxConv->userKey,
574  contextInfoPtr->ctxConv->userKeyLength );
575  }
576  break;
577 
578  case CONTEXT_MAC:
579  if( contextInfoPtr->ctxMAC->userKeyLength < MIN_KEYSIZE || \
580  contextInfoPtr->ctxMAC->userKeyLength > keyDataLen )
581  {
582  DEBUG_DIAG(( "Key data is too long to export" ));
583  assert( DEBUG_WARN );
584  status = CRYPT_ERROR_OVERFLOW;
585  }
586  else
587  {
588  memcpy( keyData, contextInfoPtr->ctxMAC->userKey,
589  contextInfoPtr->ctxMAC->userKeyLength );
590  }
591  break;
592 
593  case CONTEXT_GENERIC:
594  if( contextInfoPtr->ctxGeneric->genericSecretLength < MIN_KEYSIZE || \
595  contextInfoPtr->ctxGeneric->genericSecretLength > keyDataLen )
596  {
597  DEBUG_DIAG(( "Key data is too long to export" ));
598  assert( DEBUG_WARN );
599  status = CRYPT_ERROR_OVERFLOW;
600  }
601  else
602  {
603  memcpy( keyData, contextInfoPtr->ctxGeneric->genericSecret,
604  contextInfoPtr->ctxGeneric->genericSecretLength );
605  }
606  break;
607 
608  default:
609  retIntError();
610  }
611  releaseObject( iCryptContext, ACCESS_CHECK_KEYACCESS, NULL );
612  return( status );
613  }
614 
616 int exportPrivateKeyData( INOUT STREAM *stream,
617  IN_HANDLE const CRYPT_CONTEXT iCryptContext,
618  IN_ENUM( KEYFORMAT ) const KEYFORMAT_TYPE formatType,
619  IN_BUFFER( accessKeyLen ) const char *accessKey,
620  IN_LENGTH_FIXED( 11 ) const int accessKeyLen )
621  {
623  int status;
624 
625  assert( isWritePtr( stream, sizeof( STREAM ) ) );
626  assert( isReadPtr( accessKey, accessKeyLen ) );
627 
628  REQUIRES( isHandleRangeValid( iCryptContext ) );
629  REQUIRES( formatType > KEYFORMAT_NONE && formatType < KEYFORMAT_LAST );
630  REQUIRES( accessKeyLen == 11 );
631 
632  /* Make sure that we really intended to call this function */
633  ENSURES( accessKeyLen == 11 && !memcmp( accessKey, "private_key", 11 ) );
634 
635  /* Make sure that we've been given a PKC context with a private key
636  loaded. This has already been checked at a higher level, but we
637  perform a sanity check here to be safe */
638  status = getObject( iCryptContext, OBJECT_TYPE_CONTEXT,
640  ( void ** ) &contextInfoPtr, CRYPT_UNUSED,
642  if( cryptStatusError( status ) )
643  return( status );
644  if( contextInfoPtr->type != CONTEXT_PKC || \
645  !( contextInfoPtr->flags & CONTEXT_FLAG_KEY_SET ) || \
646  ( contextInfoPtr->flags & CONTEXT_FLAG_ISPUBLICKEY ) )
647  {
648  releaseObject( iCryptContext, ACCESS_CHECK_KEYACCESS, NULL );
649  return( CRYPT_ARGERROR_OBJECT );
650  }
651 
652  /* Export the key data from the context */
653  status = contextInfoPtr->ctxPKC->writePrivateKeyFunction( stream,
654  contextInfoPtr, formatType,
655  accessKey, accessKeyLen );
656  releaseObject( iCryptContext, ACCESS_CHECK_KEYACCESS, NULL );
657  return( status );
658  }
659 
661 int importPrivateKeyData( INOUT STREAM *stream,
662  IN_HANDLE const CRYPT_CONTEXT iCryptContext,
663  IN_ENUM( KEYFORMAT ) \
664  const KEYFORMAT_TYPE formatType )
665  {
667  int status;
668 
669  assert( isWritePtr( stream, sizeof( STREAM ) ) );
670 
671  REQUIRES( isHandleRangeValid( iCryptContext ) );
672  REQUIRES( formatType > KEYFORMAT_NONE && formatType < KEYFORMAT_LAST );
673 
674  /* Make sure that we've been given a PKC context with no private key
675  loaded. This has already been checked at a higher level, but we
676  perform a sanity check here to be safe */
677  status = getObject( iCryptContext, OBJECT_TYPE_CONTEXT,
679  ( void ** ) &contextInfoPtr, CRYPT_UNUSED,
681  if( cryptStatusError( status ) )
682  return( status );
683  if( contextInfoPtr->type != CONTEXT_PKC || \
684  ( contextInfoPtr->flags & CONTEXT_FLAG_KEY_SET ) || \
685  ( contextInfoPtr->flags & CONTEXT_FLAG_ISPUBLICKEY ) )
686  {
687  releaseObject( iCryptContext, ACCESS_CHECK_KEYACCESS, NULL );
688  return( CRYPT_ARGERROR_OBJECT );
689  }
690 
691  /* Import the key data into the context */
692  status = contextInfoPtr->ctxPKC->readPrivateKeyFunction( stream,
693  contextInfoPtr, formatType );
694  if( cryptStatusOK( status ) )
695  {
696  /* If everything went OK, perform an internal load that uses the
697  values already present in the context */
698  status = contextInfoPtr->loadKeyFunction( contextInfoPtr, NULL, 0 );
699  if( cryptStatusOK( status ) && formatType == KEYFORMAT_PRIVATE_OLD )
700  {
701  /* This format is unusual in that it stores the public-key data
702  in encrypted form alongside the private-key data, so that the
703  public key is read as part of the private key rather than
704  being set as a CRYPT_IATTRIBUTE_KEY_xxx_PARTIAL attribute.
705  Because of this it bypasses the standard keyID-calculation
706  process that occurs on public-key load, so we have to
707  explicitly calculate the keyID data here */
708  status = contextInfoPtr->ctxPKC->calculateKeyIDFunction( contextInfoPtr );
709  }
710  if( cryptStatusOK( status ) )
711  {
712  krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE,
714  CRYPT_IATTRIBUTE_INITIALISED );
715  contextInfoPtr->flags |= CONTEXT_FLAG_KEY_SET;
716  }
717  else
718  {
719  /* If the problem was indicated as a function argument error,
720  map it to a more appropriate code. The most appropriate code
721  at this point is CRYPT_ERROR_INVALID since a bad-data error
722  will be returned as an explicit CRYPT_ERROR_BADDATA while a
723  parameter error indicates that one or more of the key
724  components failed a validity check */
725  if( cryptArgError( status ) )
726  status = CRYPT_ERROR_INVALID;
727  }
728  }
729  releaseObject( iCryptContext, ACCESS_CHECK_KEYACCESS, NULL );
730  return( status );
731  }