1 /****************************************************************************
2 * *
3 * Internal Message Handlers *
4 * Copyright Peter Gutmann 1997-2004 *
5 * *
6 ****************************************************************************/
7
8 #if defined( INC_ALL )
9 #include "crypt.h"
10 #include "acl.h"
11 #include "kernel.h"
12 #else
13 #include "crypt.h"
14 #include "kernel/acl.h"
15 #include "kernel/kernel.h"
16 #endif /* Compiler-specific includes */
17
18 /* A pointer to the kernel data block */
19
20 static KERNEL_DATA *krnlData = NULL;
21
22 /****************************************************************************
23 * *
24 * Dependency ACLs *
25 * *
26 ****************************************************************************/
27
28 /* The ACL tables for each object dependency type */
29
30 static const DEPENDENCY_ACL FAR_BSS dependencyACLTbl[] = {
31 /* Envelopes and sessions can have conventional encryption and MAC
32 contexts attached */
33 MK_DEPACL( OBJECT_TYPE_ENVELOPE, ST_NONE, ST_ENV_ANY, ST_NONE, \
34 OBJECT_TYPE_CONTEXT, ST_CTX_CONV | ST_CTX_MAC, ST_NONE, ST_NONE ),
35 MK_DEPACL( OBJECT_TYPE_SESSION, ST_NONE, ST_NONE, ST_SESS_ANY, \
36 OBJECT_TYPE_CONTEXT, ST_CTX_CONV | ST_CTX_MAC, ST_NONE, ST_NONE ),
37
38 /* PKC contexts can have certs attached and vice versa. Since the
39 certificate can change the permissions on the context, we set the
40 DEP_FLAG_UPDATEDEP flag to ensure that the cert permissions get
41 reflected onto the context */
42 MK_DEPACL_EX( OBJECT_TYPE_CONTEXT, ST_CTX_PKC, ST_NONE, ST_NONE, \
43 OBJECT_TYPE_CERTIFICATE, ST_CERT_ANY, ST_NONE, ST_NONE,
44 DEP_FLAG_UPDATEDEP ),
45 MK_DEPACL_EX( OBJECT_TYPE_CERTIFICATE, ST_CERT_ANY, ST_NONE, ST_NONE, \
46 OBJECT_TYPE_CONTEXT, ST_CTX_PKC, ST_NONE, ST_NONE,
47 DEP_FLAG_UPDATEDEP ),
48
49 /* Contexts can have crypto devices attached */
50 MK_DEPACL( OBJECT_TYPE_CONTEXT, ST_CTX_ANY, ST_NONE, ST_NONE, \
51 OBJECT_TYPE_DEVICE, ST_NONE, ST_DEV_ANY_STD, ST_NONE ),
52
53 /* Hardware crypto devices can have PKCS #15 storage objects attached */
54 MK_DEPACL( OBJECT_TYPE_DEVICE, ST_NONE, ST_DEV_HW, ST_NONE, \
55 OBJECT_TYPE_KEYSET, ST_NONE, ST_KEYSET_FILE, ST_NONE ),
56
57 /* Anything can have the system device attached, since all objects not
58 created via crypto devices are created via the system device */
59 MK_DEPACL( OBJECT_TYPE_CONTEXT, ST_CTX_ANY, ST_NONE, ST_NONE, \
60 OBJECT_TYPE_DEVICE, ST_NONE, ST_DEV_SYSTEM, ST_NONE ),
61 MK_DEPACL( OBJECT_TYPE_CERTIFICATE, ST_CERT_ANY, ST_NONE, ST_NONE, \
62 OBJECT_TYPE_DEVICE, ST_NONE, ST_DEV_SYSTEM, ST_NONE ),
63 MK_DEPACL( OBJECT_TYPE_KEYSET, ST_NONE, ST_KEYSET_ANY, ST_NONE, \
64 OBJECT_TYPE_DEVICE, ST_NONE, ST_DEV_SYSTEM, ST_NONE ),
65 MK_DEPACL( OBJECT_TYPE_ENVELOPE, ST_NONE, ST_ENV_ANY, ST_NONE, \
66 OBJECT_TYPE_DEVICE, ST_NONE, ST_DEV_SYSTEM, ST_NONE ),
67 MK_DEPACL( OBJECT_TYPE_SESSION, ST_NONE, ST_NONE, ST_SESS_ANY, \
68 OBJECT_TYPE_DEVICE, ST_NONE, ST_DEV_SYSTEM, ST_NONE ),
69 MK_DEPACL( OBJECT_TYPE_DEVICE, ST_NONE, ST_DEV_ANY_STD, ST_NONE, \
70 OBJECT_TYPE_DEVICE, ST_NONE, ST_DEV_SYSTEM, ST_NONE ),
71 MK_DEPACL( OBJECT_TYPE_USER, ST_NONE, ST_NONE, ST_USER_ANY, \
72 OBJECT_TYPE_DEVICE, ST_NONE, ST_DEV_SYSTEM, ST_NONE ),
73
74 /* End-of-ACL marker */
75 MK_DEPACL_END(), MK_DEPACL_END()
76 };
77
78 /****************************************************************************
79 * *
80 * Utility Functions *
81 * *
82 ****************************************************************************/
83
84 /* Update an action permission. This implements a ratchet that only allows
85 permissions to be made more restrictive after they've initially been set,
86 so that once a permission is set to a given level it can't be set back to
87 a less restrictive one (i.e. it's a write-up policy) */
88
89 CHECK_RETVAL \
updateActionPerms(IN_FLAGS (ACTION_PERM)int currentPerm,IN_FLAGS (ACTION_PERM)const int newPerm)90 static int updateActionPerms( IN_FLAGS( ACTION_PERM ) int currentPerm,
91 IN_FLAGS( ACTION_PERM ) const int newPerm )
92 {
93 int permMask = ACTION_PERM_MASK, i;
94
95 /* Preconditions: The permissions are valid */
96 REQUIRES( currentPerm > 0 && currentPerm <= ACTION_PERM_ALL_MAX );
97 REQUIRES( newPerm > 0 && newPerm <= ACTION_PERM_ALL_MAX );
98
99 /* For each permission, update its value if the new setting is more
100 restrictive than the current one. Since smaller values are more
101 restrictive, we can do a simple range comparison and replace the
102 existing value if it's larger than the new one */
103 for( i = 0; i < ACTION_PERM_COUNT; i++ )
104 {
105 if( ( newPerm & permMask ) < ( currentPerm & permMask ) )
106 currentPerm = ( currentPerm & ~permMask ) | ( newPerm & permMask );
107 permMask <<= ACTION_PERM_BITS;
108 }
109
110 /* Postcondition: The new permission is at least as restrictive (or more
111 so) than the old one */
112 FORALL( i, 0, ACTION_PERM_COUNT,
113 ( currentPerm & ( ACTION_PERM_MASK << ( i * ACTION_PERM_BITS ) ) ) <= \
114 ( newPerm & ( ACTION_PERM_MASK << ( i * ACTION_PERM_BITS ) ) ) );
115
116 return( currentPerm );
117 }
118
119 /* Update the action permissions for an object based on the composite
120 permissions for it and a dependent object. This is a special-case
121 function because it has to operate with the object table unlocked. This
122 is necessary because the dependent object may be owned by another thread,
123 and if we were to leave the object table locked the two would deadlock if
124 we were sending the object a message while owning the object table at the
125 same time that the other thread was sending a message while owning the
126 object.
127
128 There is one (rather unlikely) potential race condition possible here in
129 which the object is destroyed and replaced by a new one while the object
130 table is unlocked, so we end up updating the action permissions for a
131 different object. To protect against this, we check the unique ID after
132 we re-lock the object table to make sure that it's the same object */
133
134 CHECK_RETVAL \
updateDependentObjectPerms(IN_HANDLE const CRYPT_HANDLE objectHandle,IN_HANDLE const CRYPT_HANDLE dependentObject)135 static int updateDependentObjectPerms( IN_HANDLE const CRYPT_HANDLE objectHandle,
136 IN_HANDLE const CRYPT_HANDLE dependentObject )
137 {
138 const OBJECT_INFO *objectTable = krnlData->objectTable;
139 const OBJECT_TYPE objectType = objectTable[ objectHandle ].type;
140 const CRYPT_CONTEXT contextHandle = \
141 ( objectType == OBJECT_TYPE_CONTEXT ) ? objectHandle : dependentObject;
142 const CRYPT_CERTIFICATE certHandle = \
143 ( objectType == OBJECT_TYPE_CERTIFICATE ) ? objectHandle : dependentObject;
144 const int uniqueID = objectTable[ objectHandle ].uniqueID;
145 int actionFlags = 0, status;
146 ORIGINAL_INT_VAR( oldPerm, objectTable[ contextHandle ].actionFlags );
147 /* Note that the above macro gives initialised-but-not-referenced
148 warnings in release builds */
149
150 /* Preconditions: Objects are valid, one is a cert and the other a
151 context, and they aren't dependent on each other (which would create
152 a dependency update loop). Note that these checks aren't performed
153 at runtime since they've already been performed by the calling
154 function, all we're doing here is establishing preconditions rather
155 than performing actual parameter checking */
156 REQUIRES( isValidObject( objectHandle ) );
157 REQUIRES( isValidHandle( dependentObject ) );
158 REQUIRES( ( objectTable[ objectHandle ].type == OBJECT_TYPE_CONTEXT && \
159 objectTable[ dependentObject ].type == OBJECT_TYPE_CERTIFICATE ) || \
160 ( objectTable[ objectHandle ].type == OBJECT_TYPE_CERTIFICATE && \
161 objectTable[ dependentObject ].type == OBJECT_TYPE_CONTEXT ) );
162 REQUIRES( objectTable[ objectHandle ].dependentObject != dependentObject || \
163 objectTable[ dependentObject ].dependentObject != objectHandle );
164
165 /* Since we're about to send messages to the dependent object, we have to
166 unlock the object table. Since we're about to hand off control to
167 other threads, we clear any object-table references since we can't
168 rely on them to be consistent when we re-lock the table */
169 objectTable = NULL;
170 MUTEX_UNLOCK( objectTable );
171
172 /* Make sure that we're not making a private key dependent on a cert,
173 which is a public-key object. We check this here rather than having
174 the caller check it because it requires having the object table
175 unlocked */
176 if( objectType == OBJECT_TYPE_CERTIFICATE && \
177 cryptStatusOK( \
178 krnlSendMessage( dependentObject, IMESSAGE_CHECK, NULL,
179 MESSAGE_CHECK_PKC_PRIVATE ) ) )
180 {
181 MUTEX_LOCK( objectTable );
182 retIntError();
183 }
184
185 /* For each action type, enable its continued use only if the cert
186 allows it. Because the certificate may not have been fully
187 initialised yet (for example if we're attaching a context to a
188 cert that's in the process of being created), we have to perform
189 a passive-container action-available check that also works on a
190 low-state object rather than a standard active-object check.
191
192 Because a key with a certificate attached indicates that it's
193 (probably) being used for some function that involves interaction
194 with a relying party (i.e. that it probably has more value than a raw
195 key with no strings attached), we set the action permission to
196 ACTION_PERM_NONE_EXTERNAL rather than allowing ACTION_PERM_ALL. This
197 both ensures that it's only used in a safe manner via the cryptlib
198 internal mechanisms, and makes sure that it's not possible to utilize
199 the signature/encryption duality of some algorithms to create a
200 signature where it's been disallowed */
201 if( cryptStatusOK( krnlSendMessage( certHandle,
202 IMESSAGE_CHECK, NULL, MESSAGE_CHECK_PKC_SIGN_AVAIL ) ) )
203 actionFlags |= \
204 MK_ACTION_PERM( MESSAGE_CTX_SIGN, ACTION_PERM_NONE_EXTERNAL );
205 if( cryptStatusOK( krnlSendMessage( certHandle,
206 IMESSAGE_CHECK, NULL, MESSAGE_CHECK_PKC_SIGCHECK_AVAIL ) ) )
207 actionFlags |= \
208 MK_ACTION_PERM( MESSAGE_CTX_SIGCHECK, ACTION_PERM_NONE_EXTERNAL );
209 if( cryptStatusOK( krnlSendMessage( certHandle,
210 IMESSAGE_CHECK, NULL, MESSAGE_CHECK_PKC_ENCRYPT_AVAIL ) ) )
211 actionFlags |= \
212 MK_ACTION_PERM( MESSAGE_CTX_ENCRYPT, ACTION_PERM_NONE_EXTERNAL );
213 if( cryptStatusOK( krnlSendMessage( certHandle,
214 IMESSAGE_CHECK, NULL, MESSAGE_CHECK_PKC_DECRYPT_AVAIL ) ) )
215 actionFlags |= \
216 MK_ACTION_PERM( MESSAGE_CTX_DECRYPT, ACTION_PERM_NONE_EXTERNAL );
217 if( cryptStatusOK( krnlSendMessage( certHandle,
218 IMESSAGE_CHECK, NULL, MESSAGE_CHECK_PKC_KA_EXPORT_AVAIL ) ) )
219 actionFlags |= \
220 MK_ACTION_PERM( MESSAGE_CTX_ENCRYPT, ACTION_PERM_NONE_EXTERNAL );
221 if( cryptStatusOK( krnlSendMessage( certHandle,
222 IMESSAGE_CHECK, NULL, MESSAGE_CHECK_PKC_KA_IMPORT_AVAIL ) ) )
223 actionFlags |= \
224 MK_ACTION_PERM( MESSAGE_CTX_DECRYPT, ACTION_PERM_NONE_EXTERNAL );
225
226 /* Inner precondition: The usage shouldn't be all-zero. Technically it
227 can be since there are bound to be certs out there broken enough to do
228 this, and certainly under the stricter compliance levels this *will*
229 happen, so we make it a warning that's only produced in debug mode */
230 if( actionFlags == 0 )
231 {
232 DEBUG_DIAG(( "Object %s is constrained by its associated "
233 "certificate object to not allow any actions",
234 getObjectDescriptionNT( objectHandle ) ));
235 assert_nofuzz( DEBUG_WARN );
236 }
237
238 /* We're done querying the dependent object, re-lock the object table,
239 reinitialise any references to it, and make sure that the original
240 object hasn't been touched */
241 MUTEX_LOCK( objectTable );
242 objectTable = krnlData->objectTable;
243 if( objectTable[ objectHandle ].uniqueID != uniqueID )
244 return( CRYPT_ERROR_SIGNALLED );
245 if( actionFlags == 0 )
246 {
247 /* See the comment above, we can't continue at this point because we
248 can't set the action permissions attribute to nothing */
249 return( CRYPT_ERROR_NOTAVAIL );
250 }
251 status = setPropertyAttribute( contextHandle, CRYPT_IATTRIBUTE_ACTIONPERMS,
252 &actionFlags );
253
254 /* Postcondition: The new permission is at least as restrictive (or more
255 so) than the old one */
256 FORALL( i, 0, ACTION_PERM_COUNT,
257 ( objectTable[ contextHandle ].actionFlags & ( ACTION_PERM_MASK << ( i * 2 ) ) ) <= \
258 ( ORIGINAL_VALUE( oldPerm ) & ( ACTION_PERM_MASK << ( i * 2 ) ) ) );
259
260 return( status );
261 }
262
263
264 /* Convert an internal object reference to an external one */
265
266 CHECK_RETVAL \
convertIntToExtRef(IN_HANDLE const int objectHandle)267 int convertIntToExtRef( IN_HANDLE const int objectHandle )
268 {
269 int status;
270
271 /* Preconditions */
272 REQUIRES( isValidObject( objectHandle ) );
273
274 /* Convert at least one internal reference to the object to an external
275 one */
276 status = incRefCount( objectHandle, 0, NULL, FALSE );
277 if( cryptStatusOK( status ) )
278 status = decRefCount( objectHandle, 0, NULL, TRUE );
279 if( cryptStatusOK( status ) )
280 return( status );
281
282 /* Recovering from an error at this point is tricky, it's a shouldn't-
283 occur condition in any case but if it does occur then the fact that
284 the object reference is in an unclear state means we can't do a
285 straight decRef(). The safest option seems to be to explicitly
286 destroy it, which usually produces the correct result but in the case
287 of something like fetching a certificate from a session or envelope
288 will lead to the session/envelope's reference being destroyed as
289 well */
290 ( void ) krnlSendNotifier( objectHandle, IMESSAGE_DESTROY );
291
292 return( status );
293 }
294
295 /****************************************************************************
296 * *
297 * Init/Shutdown Functions *
298 * *
299 ****************************************************************************/
300
301 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
initInternalMsgs(INOUT KERNEL_DATA * krnlDataPtr)302 int initInternalMsgs( INOUT KERNEL_DATA *krnlDataPtr )
303 {
304 int i;
305
306 assert( isWritePtr( krnlDataPtr, sizeof( KERNEL_DATA ) ) );
307
308 /* If we're running a fuzzing build, skip the lengthy self-checks */
309 #ifdef CONFIG_FUZZ
310 krnlData = krnlDataPtr;
311 return( CRYPT_OK );
312 #endif /* CONFIG_FUZZ */
313
314 /* Perform a consistency check on the object dependency ACL */
315 for( i = 0; dependencyACLTbl[ i ].type != OBJECT_TYPE_NONE && \
316 i < FAILSAFE_ARRAYSIZE( dependencyACLTbl, DEPENDENCY_ACL );
317 i++ )
318 {
319 const DEPENDENCY_ACL *dependencyACL = &dependencyACLTbl[ i ];
320
321 ENSURES( dependencyACL->type > OBJECT_TYPE_NONE && \
322 dependencyACL->type < OBJECT_TYPE_LAST && \
323 dependencyACL->dType > OBJECT_TYPE_NONE && \
324 dependencyACL->dType < OBJECT_TYPE_LAST );
325 ENSURES( !( dependencyACL->subTypeA & ( SUBTYPE_CLASS_B | \
326 SUBTYPE_CLASS_C ) ) && \
327 !( dependencyACL->subTypeB & ( SUBTYPE_CLASS_A | \
328 SUBTYPE_CLASS_C ) ) && \
329 !( dependencyACL->subTypeC & ( SUBTYPE_CLASS_A | \
330 SUBTYPE_CLASS_B ) ) );
331 ENSURES( !( dependencyACL->dSubTypeA & ( SUBTYPE_CLASS_B | \
332 SUBTYPE_CLASS_C ) ) && \
333 !( dependencyACL->dSubTypeB & ( SUBTYPE_CLASS_A | \
334 SUBTYPE_CLASS_C ) ) && \
335 !( dependencyACL->dSubTypeC & ( SUBTYPE_CLASS_A | \
336 SUBTYPE_CLASS_B ) ) );
337 }
338 ENSURES( i < FAILSAFE_ARRAYSIZE( dependencyACLTbl, DEPENDENCY_ACL ) );
339
340 /* Set up the reference to the kernel data block */
341 krnlData = krnlDataPtr;
342
343 return( CRYPT_OK );
344 }
345
endInternalMsgs(void)346 void endInternalMsgs( void )
347 {
348 krnlData = NULL;
349 }
350
351 /****************************************************************************
352 * *
353 * Get/Set Property Attributes *
354 * *
355 ****************************************************************************/
356
357 /* Get/set object property attributes. We differentiate between a small
358 number of user-accessible properties such as the object's owner, and
359 properties that are only accessible by cryptlib. The user-accessible
360 properties can be locked, which makes them immutable (at least to being
361 explicitly set, they can still be implicitly altered, for example setting
362 a new object owner decrements the forwardcount value) and also unreadable
363 by the user */
364
365 CHECK_RETVAL STDC_NONNULL_ARG( ( 3 ) ) \
getPropertyAttribute(IN_HANDLE const int objectHandle,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute,OUT_BUFFER_FIXED_C (sizeof (int))void * messageDataPtr)366 int getPropertyAttribute( IN_HANDLE const int objectHandle,
367 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute,
368 OUT_BUFFER_FIXED_C( sizeof( int ) ) void *messageDataPtr )
369 {
370 const OBJECT_INFO *objectInfoPtr = &krnlData->objectTable[ objectHandle ];
371 int *valuePtr = ( int * ) messageDataPtr;
372
373 assert( isWritePtr( messageDataPtr, sizeof( int ) ) );
374
375 /* Preconditions */
376 REQUIRES( isValidObject( objectHandle ) );
377 REQUIRES( attribute == CRYPT_PROPERTY_OWNER || \
378 attribute == CRYPT_PROPERTY_FORWARDCOUNT || \
379 attribute == CRYPT_PROPERTY_LOCKED || \
380 attribute == CRYPT_PROPERTY_USAGECOUNT || \
381 attribute == CRYPT_IATTRIBUTE_TYPE || \
382 attribute == CRYPT_IATTRIBUTE_SUBTYPE || \
383 attribute == CRYPT_IATTRIBUTE_STATUS || \
384 attribute == CRYPT_IATTRIBUTE_INTERNAL || \
385 attribute == CRYPT_IATTRIBUTE_ACTIONPERMS );
386
387 switch( attribute )
388 {
389 /* User-accessible properties */
390 case CRYPT_PROPERTY_OWNER:
391 /* We allow this to be read since its value can be determined
392 anyway with a trial access */
393 if( !( objectInfoPtr->flags & OBJECT_FLAG_OWNED ) )
394 return( CRYPT_ERROR_NOTINITED );
395 #ifdef USE_THREADS
396 /* A small number of implementations use non-scalar thread IDs,
397 which we can't easily handle when all that we have is an
398 integer handle. However, the need to bind threads to objects
399 only exists because of Win32 security holes arising from the
400 ability to perform thread injection, so this isn't a big
401 issue */
402 #ifdef NONSCALAR_HANDLES
403 if( sizeof( objectInfoPtr->objectOwner ) > sizeof( int ) )
404 return( CRYPT_ERROR_NOTAVAIL );
405 #endif /* NONSCALAR_HANDLES */
406 *valuePtr = ( int ) objectInfoPtr->objectOwner;
407 #else
408 *valuePtr = 0;
409 #endif /* USE_THREADS */
410 break;
411
412 case CRYPT_PROPERTY_FORWARDCOUNT:
413 if( objectInfoPtr->flags & OBJECT_FLAG_ATTRLOCKED )
414 return( CRYPT_ERROR_PERMISSION );
415 *valuePtr = objectInfoPtr->forwardCount;
416 break;
417
418 case CRYPT_PROPERTY_LOCKED:
419 /* We allow this to be read since its value can be determined
420 anyway with a trial write */
421 *( ( BOOLEAN * ) messageDataPtr ) = \
422 ( objectInfoPtr->flags & OBJECT_FLAG_ATTRLOCKED ) ? \
423 TRUE : FALSE;
424 break;
425
426 case CRYPT_PROPERTY_USAGECOUNT:
427 *valuePtr = objectInfoPtr->usageCount;
428 break;
429
430 /* Internal properties */
431 case CRYPT_IATTRIBUTE_TYPE:
432 *valuePtr = objectInfoPtr->type;
433 break;
434
435 case CRYPT_IATTRIBUTE_SUBTYPE:
436 *valuePtr = objectInfoPtr->subType;
437 break;
438
439 case CRYPT_IATTRIBUTE_STATUS:
440 *valuePtr = objectInfoPtr->flags & OBJECT_FLAGMASK_STATUS;
441 break;
442
443 case CRYPT_IATTRIBUTE_INTERNAL:
444 *( ( BOOLEAN * ) messageDataPtr ) = \
445 ( objectInfoPtr->flags & OBJECT_FLAG_INTERNAL ) ? \
446 TRUE : FALSE;
447 break;
448
449 case CRYPT_IATTRIBUTE_ACTIONPERMS:
450 *valuePtr = objectInfoPtr->actionFlags;
451 break;
452
453 default:
454 retIntError();
455 }
456
457 return( CRYPT_OK );
458 }
459
460 CHECK_RETVAL STDC_NONNULL_ARG( ( 3 ) ) \
setPropertyAttribute(IN_HANDLE const int objectHandle,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute,IN_BUFFER_C (sizeof (int))void * messageDataPtr)461 int setPropertyAttribute( IN_HANDLE const int objectHandle,
462 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute,
463 IN_BUFFER_C( sizeof( int ) ) void *messageDataPtr )
464 {
465 OBJECT_INFO *objectInfoPtr = &krnlData->objectTable[ objectHandle ];
466 const int value = *( ( int * ) messageDataPtr );
467
468 assert( isReadPtr( messageDataPtr, sizeof( int ) ) );
469
470 /* Preconditions */
471 REQUIRES( isValidObject( objectHandle ) );
472 REQUIRES( attribute == CRYPT_PROPERTY_HIGHSECURITY || \
473 attribute == CRYPT_PROPERTY_OWNER || \
474 attribute == CRYPT_PROPERTY_FORWARDCOUNT || \
475 attribute == CRYPT_PROPERTY_LOCKED || \
476 attribute == CRYPT_PROPERTY_USAGECOUNT || \
477 attribute == CRYPT_IATTRIBUTE_STATUS || \
478 attribute == CRYPT_IATTRIBUTE_INTERNAL || \
479 attribute == CRYPT_IATTRIBUTE_ACTIONPERMS || \
480 attribute == CRYPT_IATTRIBUTE_LOCKED );
481 REQUIRES( objectHandle >= NO_SYSTEM_OBJECTS || \
482 attribute == CRYPT_IATTRIBUTE_STATUS );
483
484 switch( attribute )
485 {
486 /* User-accessible properties */
487 case CRYPT_PROPERTY_HIGHSECURITY:
488 /* This is a combination property that makes an object owned,
489 non-forwardable, and locked */
490 if( objectInfoPtr->flags & OBJECT_FLAG_ATTRLOCKED )
491 return( CRYPT_ERROR_PERMISSION );
492 #ifdef USE_THREADS
493 objectInfoPtr->objectOwner = THREAD_SELF();
494 #endif /* USE_THREADS */
495 objectInfoPtr->forwardCount = 0;
496 objectInfoPtr->flags |= OBJECT_FLAG_ATTRLOCKED | OBJECT_FLAG_OWNED;
497 break;
498
499 case CRYPT_PROPERTY_OWNER:
500 /* This property can still be changed (even if the object is
501 locked) until the forwarding count drops to zero, otherwise
502 locking the object would prevent any forwarding */
503 if( objectInfoPtr->forwardCount != CRYPT_UNUSED )
504 {
505 if( objectInfoPtr->forwardCount <= 0 )
506 return( CRYPT_ERROR_PERMISSION );
507 objectInfoPtr->forwardCount--;
508 }
509 if( value == CRYPT_UNUSED )
510 objectInfoPtr->flags &= ~OBJECT_FLAG_OWNED;
511 else
512 {
513 #if defined( USE_THREADS )
514 /* See the comment in getPropertyAttribute() about the use
515 of scalar vs. non-scalar thread types */
516 #ifdef NONSCALAR_HANDLES
517 if( sizeof( objectInfoPtr->objectOwner ) <= sizeof( int ) )
518 #endif /* NONSCALAR_HANDLES */
519 {
520 objectInfoPtr->objectOwner = ( THREAD_HANDLE ) value;
521 objectInfoPtr->flags |= OBJECT_FLAG_OWNED;
522 }
523 #endif /* USE_THREADS */
524 }
525 break;
526
527 case CRYPT_PROPERTY_FORWARDCOUNT:
528 if( objectInfoPtr->flags & OBJECT_FLAG_ATTRLOCKED )
529 return( CRYPT_ERROR_PERMISSION );
530 if( objectInfoPtr->forwardCount != CRYPT_UNUSED && \
531 objectInfoPtr->forwardCount < value )
532 {
533 /* Once set the forward count can only be decreased, never
534 increased */
535 return( CRYPT_ERROR_PERMISSION );
536 }
537 objectInfoPtr->forwardCount = value;
538 break;
539
540 case CRYPT_PROPERTY_LOCKED:
541 /* Precondition: This property can only be set to true */
542 REQUIRES( value != FALSE );
543
544 objectInfoPtr->flags |= OBJECT_FLAG_ATTRLOCKED;
545 break;
546
547 case CRYPT_PROPERTY_USAGECOUNT:
548 if( objectInfoPtr->flags & OBJECT_FLAG_ATTRLOCKED || \
549 ( objectInfoPtr->usageCount != CRYPT_UNUSED && \
550 objectInfoPtr->usageCount < value ) )
551 {
552 /* Once set the usage count can only be decreased, never
553 increased */
554 return( CRYPT_ERROR_PERMISSION );
555 }
556 objectInfoPtr->usageCount = value;
557 break;
558
559 /* Internal properties */
560 case CRYPT_IATTRIBUTE_STATUS:
561 /* We're clearing an error/abnormal state */
562 REQUIRES( value == CRYPT_OK );
563
564 if( isInvalidObjectState( objectHandle ) )
565 {
566 /* If the object is in an abnormal state, we can only (try to)
567 return it back to the normal state after the problem is
568 resolved */
569 REQUIRES( value == CRYPT_OK );
570
571 /* If we're processing a notification from the caller that
572 the object init is complete and the object was destroyed
573 while it was being created (which sets its state to
574 CRYPT_ERROR_SIGNALLED), tell the caller to convert the
575 message to a destroy object message unless it's a system
576 object, which can't be explicitly destroyed. In this case
577 we just return an error so the cryptlib init fails */
578 if( objectInfoPtr->flags & OBJECT_FLAG_SIGNALLED )
579 {
580 return( ( objectHandle < NO_SYSTEM_OBJECTS ) ?
581 CRYPT_ERROR_SIGNALLED : OK_SPECIAL );
582 }
583
584 /* We're transitioning the object to the initialised state */
585 REQUIRES( objectInfoPtr->flags & OBJECT_FLAG_NOTINITED );
586 objectInfoPtr->flags &= ~OBJECT_FLAG_NOTINITED;
587 ENSURES( !( objectInfoPtr->flags & OBJECT_FLAG_NOTINITED ) );
588 break;
589 }
590
591 /* Postcondition: The object is in a valid state */
592 ENSURES( !isInvalidObjectState( objectHandle ) );
593
594 break;
595
596 case CRYPT_IATTRIBUTE_INTERNAL:
597 {
598 int status;
599
600 /* Internal objects can be made external after creation or fetch
601 from another object like a keyset, but not the other way
602 round */
603 REQUIRES( value == FALSE );
604
605 /* Make the object externally accessible */
606 REQUIRES( isInternalObject( objectHandle ) );
607 objectInfoPtr->flags &= ~OBJECT_FLAG_INTERNAL;
608
609 /* Now that the object is external we need to convert at least
610 one internal reference to it to an external one */
611 status = convertIntToExtRef( objectHandle );
612 if( cryptStatusError( status ) )
613 return( status );
614
615 break;
616 }
617
618 case CRYPT_IATTRIBUTE_ACTIONPERMS:
619 {
620 const int newPerm = \
621 updateActionPerms( objectInfoPtr->actionFlags, value );
622
623 if( cryptStatusError( newPerm ) )
624 return( newPerm );
625 objectInfoPtr->actionFlags = newPerm;
626 break;
627 }
628
629 case CRYPT_IATTRIBUTE_LOCKED:
630 /* Incremement or decrement the object's lock count depending on
631 whether we're locking or unlocking it */
632 if( value )
633 {
634 /* Precondition: The lock count is positive or zero */
635 REQUIRES( objectInfoPtr->lockCount >= 0 );
636
637 objectInfoPtr->lockCount++;
638
639 ENSURES( objectInfoPtr->lockCount < MAX_INTLENGTH );
640 #ifdef USE_THREADS
641 objectInfoPtr->lockOwner = THREAD_SELF();
642 #endif /* USE_THREADS */
643 }
644 else
645 {
646 /* Precondition: The lock count is positive */
647 REQUIRES( objectInfoPtr->lockCount > 0 );
648
649 objectInfoPtr->lockCount--;
650
651 ENSURES( objectInfoPtr->lockCount >= 0 );
652 }
653
654 /* If it's a certificate, notify it that it should save/restore
655 its internal state */
656 if( objectInfoPtr->type == OBJECT_TYPE_CERTIFICATE )
657 {
658 const MESSAGE_FUNCTION messageFunction = \
659 FNPTR_GET( objectInfoPtr->messageFunction );
660
661 ENSURES( messageFunction != NULL );
662 ( void ) messageFunction( objectInfoPtr->objectPtr,
663 MESSAGE_CHANGENOTIFY, messageDataPtr,
664 MESSAGE_CHANGENOTIFY_STATE );
665 }
666 break;
667
668 default:
669 retIntError();
670 }
671
672 return( CRYPT_OK );
673 }
674
675 /****************************************************************************
676 * *
677 * Update Internal Properties *
678 * *
679 ****************************************************************************/
680
681 /* Increment/decrement the reference counts for an object. Since references
682 can be either internal or external, we have to handle the two separately.
683 If the last external reference is removed then the object becomes
684 internal-only, if all references are removed then the object is
685 destroyed.
686
687 There's an additional reference-count manipulation facility in the
688 attribute-handling mechanism for CRYPT_IATTRIBUTE_INTERNAL, which
689 transfers a reference from internal to external when making an object
690 external */
691
692 CHECK_RETVAL \
incRefCount(IN_HANDLE const int objectHandle,STDC_UNUSED const int dummy1,STDC_UNUSED const void * dummy2,const BOOLEAN isInternal)693 int incRefCount( IN_HANDLE const int objectHandle,
694 STDC_UNUSED const int dummy1,
695 STDC_UNUSED const void *dummy2,
696 const BOOLEAN isInternal )
697 {
698 OBJECT_INFO *objectTable = krnlData->objectTable;
699 int *referenceCountPtr = isInternal ? \
700 &objectTable[ objectHandle ].intRefCount : \
701 &objectTable[ objectHandle ].extRefCount;
702 ORIGINAL_INT_VAR( oldRefCount, *referenceCountPtr );
703
704 /* Preconditions. Since there are two reference counts, the one that
705 we're updating can be zero if the other one is nonzero */
706 REQUIRES( isValidObject( objectHandle ) );
707 REQUIRES( *referenceCountPtr >= 0 && \
708 *referenceCountPtr < MAX_INTLENGTH_SHORT );
709
710 /* Make sure that we don't try and increment a reference count a
711 suspicious number of times */
712 if( *referenceCountPtr >= MAX_INTLENGTH_SHORT - 1 )
713 return( CRYPT_ARGERROR_OBJECT );
714
715 /* Increment the object's reference count */
716 ( *referenceCountPtr )++;
717
718 /* Postcondition: We incremented the reference count and it's now greater
719 than zero (the ground state) */
720 ENSURES( *referenceCountPtr >= 1 && \
721 *referenceCountPtr < MAX_INTLENGTH_SHORT );
722 ENSURES( *referenceCountPtr == ORIGINAL_VALUE( oldRefCount ) + 1 );
723
724 return( CRYPT_OK );
725 }
726
727 CHECK_RETVAL \
decRefCount(IN_HANDLE const int objectHandle,STDC_UNUSED const int dummy1,STDC_UNUSED const void * dummy2,const BOOLEAN isInternal)728 int decRefCount( IN_HANDLE const int objectHandle,
729 STDC_UNUSED const int dummy1,
730 STDC_UNUSED const void *dummy2,
731 const BOOLEAN isInternal )
732 {
733 OBJECT_INFO *objectTable = krnlData->objectTable;
734 int *referenceCountPtr = isInternal ? \
735 &objectTable[ objectHandle ].intRefCount : \
736 &objectTable[ objectHandle ].extRefCount;
737 int status;
738 ORIGINAL_INT_VAR( oldRefCount, *referenceCountPtr );
739
740 /* Preconditions */
741 REQUIRES( isValidObject( objectHandle ) );
742 REQUIRES( *referenceCountPtr >= 1 && \
743 *referenceCountPtr < MAX_INTLENGTH_SHORT );
744
745 /* If the last external reference is about to be destroyed, make the
746 object internal. This marks it as invalid for any external access,
747 so that to the caller it looks like it's been destroyed even if its
748 internal reference count keeps it active */
749 if( !isInternal && !isInternalObject( objectHandle ) && \
750 *referenceCountPtr <= 1 )
751 {
752 objectTable[ objectHandle ].flags |= OBJECT_FLAG_INTERNAL;
753 ENSURES( isInternalObject( objectHandle ) );
754 }
755
756 /* Decrement the object's reference count */
757 ( *referenceCountPtr )--;
758
759 /* Postconditions: We decremented the reference count and it's greater
760 than or equal to zero (the ground state) */
761 ENSURES( *referenceCountPtr >= 0 && \
762 *referenceCountPtr < MAX_INTLENGTH_SHORT - 1 );
763 ENSURES( *referenceCountPtr == ORIGINAL_VALUE( oldRefCount ) - 1 );
764
765 /* If there are still references to the object present, there's nothing
766 further to do */
767 if( objectTable[ objectHandle ].intRefCount > 0 || \
768 objectTable[ objectHandle ].extRefCount > 0 )
769 return( CRYPT_OK );
770
771 /* We're about to destroy the object, all references to it have been
772 removed */
773 ENSURES( objectTable[ objectHandle ].extRefCount == 0 && \
774 objectTable[ objectHandle ].intRefCount == 0 );
775
776 /* Destroy the object. Since this can entail arbitrary amounts of
777 processing during the object shutdown phase, we have to unlock the
778 object table around the call */
779 MUTEX_UNLOCK( objectTable );
780 status = krnlSendNotifier( objectHandle, IMESSAGE_DESTROY );
781 MUTEX_LOCK( objectTable );
782
783 return( status );
784 }
785
786 /* Get/set dependent objects for an object */
787
788 CHECK_RETVAL STDC_NONNULL_ARG( ( 3 ) ) \
getDependentObject(IN_HANDLE const int objectHandle,const int targetType,IN_BUFFER_C (sizeof (int))const void * messageDataPtr,STDC_UNUSED const BOOLEAN dummy)789 int getDependentObject( IN_HANDLE const int objectHandle,
790 const int targetType,
791 IN_BUFFER_C( sizeof( int ) ) \
792 const void *messageDataPtr,
793 /* This is a bit of a lie since we actually
794 return the dependent object through this
795 pointer, however making it non-const means
796 that we'd have to also un-const every other
797 use of this parameter in all other functions
798 accessed via this function pointer */
799 STDC_UNUSED const BOOLEAN dummy )
800 {
801 int *valuePtr = ( int * ) messageDataPtr, status;
802
803 assert( isReadPtr( messageDataPtr, sizeof( int ) ) );
804
805 /* Preconditions */
806 REQUIRES( isValidObject( objectHandle ) );
807 REQUIRES( isValidType( targetType ) );
808
809 /* Clear return value */
810 *valuePtr = CRYPT_ERROR;
811
812 status = findTargetType( objectHandle, valuePtr, targetType );
813 if( cryptStatusError( status ) )
814 {
815 /* Postconditions: No dependent object found */
816 ENSURES( *valuePtr == CRYPT_ERROR );
817
818 return( CRYPT_ARGERROR_OBJECT );
819 }
820
821 /* Postconditions: We found a dependent object */
822 ENSURES( isValidObject( *valuePtr ) && \
823 isSameOwningObject( *valuePtr, objectHandle ) );
824
825 return( CRYPT_OK );
826 }
827
828 CHECK_RETVAL STDC_NONNULL_ARG( ( 3 ) ) \
setDependentObject(IN_HANDLE const int objectHandle,IN_ENUM (SETDEP_OPTION)const int option,IN_BUFFER_C (sizeof (int))const void * messageDataPtr,STDC_UNUSED const BOOLEAN dummy)829 int setDependentObject( IN_HANDLE const int objectHandle,
830 IN_ENUM( SETDEP_OPTION ) const int option,
831 IN_BUFFER_C( sizeof( int ) ) \
832 const void *messageDataPtr,
833 STDC_UNUSED const BOOLEAN dummy )
834 {
835 OBJECT_INFO *objectTable = krnlData->objectTable;
836 OBJECT_INFO *objectInfoPtr = &objectTable[ objectHandle ];
837 const OBJECT_INFO *dependentObjectInfoPtr;
838 const int dependentObject = *( ( int * ) messageDataPtr );
839 const DEPENDENCY_ACL *dependencyACL = NULL;
840 int *objectHandlePtr, i, status;
841
842 assert( isReadPtr( messageDataPtr, sizeof( int ) ) );
843
844 /* Preconditions: Parameters are valid */
845 REQUIRES( isValidObject( objectHandle ) );
846 REQUIRES( option == SETDEP_OPTION_NOINCREF || \
847 option == SETDEP_OPTION_INCREF );
848 REQUIRES( isValidHandle( dependentObject ) );
849
850 /* Make sure that the object is valid, it may have been signalled after
851 the message was sent */
852 if( !isValidObject( dependentObject ) )
853 return( CRYPT_ERROR_SIGNALLED );
854 dependentObjectInfoPtr = &objectTable[ dependentObject ];
855 if( dependentObjectInfoPtr->type == OBJECT_TYPE_DEVICE )
856 objectHandlePtr = &objectInfoPtr->dependentDevice;
857 else
858 objectHandlePtr = &objectInfoPtr->dependentObject;
859
860 /* Basic validity checks: There can't already be a dependent object set */
861 if( *objectHandlePtr != CRYPT_ERROR )
862 {
863 /* There's already a dependent object present and we're trying to
864 overwrite it with a new one, something is seriously wrong */
865 retIntError();
866 }
867
868 /* More complex validity checks to ensure that the object table is
869 consistent: The object isn't already dependent on the dependent object
870 (making the dependent object then dependent on the object would
871 create a loop), and the object won't be dependent on its own object
872 type unless it's a device dependent on the system device */
873 if( ( ( ( objectInfoPtr->type == OBJECT_TYPE_DEVICE ) ? \
874 dependentObjectInfoPtr->dependentDevice : \
875 dependentObjectInfoPtr->dependentObject ) == objectHandle ) || \
876 ( objectInfoPtr->type == dependentObjectInfoPtr->type && \
877 dependentObject != SYSTEM_OBJECT_HANDLE ) )
878 retIntError();
879
880 /* Find the dependency ACL entry for this object/dependent object
881 combination. Since there can be more than one dependent object
882 type for an object, we check subtypes as well */
883 for( i = 0; dependencyACLTbl[ i ].type != OBJECT_TYPE_NONE && \
884 i < FAILSAFE_ARRAYSIZE( dependencyACLTbl, DEPENDENCY_ACL );
885 i++ )
886 {
887 if( dependencyACLTbl[ i ].type == objectInfoPtr->type && \
888 dependencyACLTbl[ i ].dType == dependentObjectInfoPtr->type && \
889 ( isValidSubtype( dependencyACLTbl[ i ].dSubTypeA, \
890 dependentObjectInfoPtr->subType ) || \
891 isValidSubtype( dependencyACLTbl[ i ].dSubTypeB, \
892 dependentObjectInfoPtr->subType ) || \
893 isValidSubtype( dependencyACLTbl[ i ].dSubTypeC, \
894 dependentObjectInfoPtr->subType ) ) )
895 {
896 dependencyACL = &dependencyACLTbl[ i ];
897 break;
898 }
899 }
900 ENSURES( i < FAILSAFE_ARRAYSIZE( dependencyACLTbl, DEPENDENCY_ACL ) );
901 ENSURES( dependencyACL != NULL );
902
903 /* Inner precondition: We have the appropriate ACL for this combination
904 of object and dependent object */
905 REQUIRES( dependencyACL->type == objectInfoPtr->type && \
906 dependencyACL->dType == dependentObjectInfoPtr->type && \
907 ( isValidSubtype( dependencyACL->dSubTypeA, \
908 dependentObjectInfoPtr->subType ) || \
909 isValidSubtype( dependencyACL->dSubTypeB, \
910 dependentObjectInfoPtr->subType ) || \
911 isValidSubtype( dependencyACL->dSubTypeC, \
912 dependentObjectInfoPtr->subType ) ) );
913
914 /* Type-specific checks. For PKC context -> cert and cert -> PKC context
915 attaches we should also check that the primary PKC object is a
916 private-key object and the dependent PKC object is a public-key object
917 to catch things like a private key depending on a (public-key) cert,
918 however this requires unlocking the object table in order to send the
919 context a check message. Since this requires additional precautions,
920 we leave it for updateDependentObjectPerms(), which has to unlock the
921 table for its own update operations */
922 ENSURES( isValidSubtype( dependencyACL->subTypeA, \
923 objectInfoPtr->subType ) || \
924 isValidSubtype( dependencyACL->subTypeB, \
925 objectInfoPtr->subType ) || \
926 isValidSubtype( dependencyACL->subTypeC, \
927 objectInfoPtr->subType ) );
928 ENSURES( isValidSubtype( dependencyACL->dSubTypeA, \
929 dependentObjectInfoPtr->subType ) || \
930 isValidSubtype( dependencyACL->dSubTypeB, \
931 dependentObjectInfoPtr->subType ) || \
932 isValidSubtype( dependencyACL->dSubTypeC, \
933 dependentObjectInfoPtr->subType ) );
934
935 /* Inner precondition */
936 REQUIRES( *objectHandlePtr == CRYPT_ERROR );
937 REQUIRES( isSameOwningObject( objectHandle, dependentObject ) );
938
939 /* Certs and contexts have special relationships in that the cert can
940 constrain the use of the context beyond its normal level. If we're
941 performing this type of object attachment, we have to adjust one
942 object's behaviour based on the permissions of the other one. We do
943 this before we increment the reference count because the latter can
944 never fail so we don't have to worry about undoing the update */
945 if( dependencyACL->flags & DEP_FLAG_UPDATEDEP )
946 {
947 status = updateDependentObjectPerms( objectHandle, dependentObject );
948 if( cryptStatusError( status ) )
949 return( status );
950 }
951
952 /* Update the dependent object's reference count if required and record
953 the new status in the object table. Dependent objects can be
954 established in one of two ways, by taking an existing object and
955 attaching it to another object (which increments its reference count,
956 since it's now being referred to by the original owner and by the
957 object it's attached to), or by creating a new object and attaching
958 it to another object (which doesn't increment the reference count
959 since it's only referred to by the controlling object). An example of
960 the former operation is adding a context from a cert request to a cert
961 (the cert request is referenced by both the caller and the cert), an
962 example of the latter operation is attaching a data-only cert to a
963 context (the cert is only referenced by the context) */
964 if( option == SETDEP_OPTION_INCREF )
965 {
966 status = incRefCount( dependentObject, 0, NULL, TRUE );
967 if( cryptStatusError( status ) )
968 return( status );
969 }
970 *objectHandlePtr = dependentObject;
971
972 /* Postconditions */
973 ENSURES( isValidObject( *objectHandlePtr ) && \
974 isSameOwningObject( objectHandle, *objectHandlePtr ) );
975
976 return( CRYPT_OK );
977 }
978
979 /* Clone an object. The older copy-on-write implementation didn't actually
980 do anything at this point except check that the access was valid and set
981 the aliased and cloned flags to indicate that the object needed to be
982 handled specially if a write access was made to it, but with the kernel
983 tracking instance data we can do a copy immediately to create two
984 distinct objects */
985
986 CHECK_RETVAL \
cloneObject(IN_HANDLE const int objectHandle,IN_HANDLE const int clonedObject,STDC_UNUSED const void * dummy1,STDC_UNUSED const BOOLEAN dummy2)987 int cloneObject( IN_HANDLE const int objectHandle,
988 IN_HANDLE const int clonedObject,
989 STDC_UNUSED const void *dummy1,
990 STDC_UNUSED const BOOLEAN dummy2 )
991 {
992 OBJECT_INFO *objectInfoPtr = &krnlData->objectTable[ objectHandle ];
993 OBJECT_INFO *clonedObjectInfoPtr = &krnlData->objectTable[ clonedObject ];
994 const MESSAGE_FUNCTION messageFunction = \
995 FNPTR_GET( objectInfoPtr->messageFunction );
996 int actionFlags, status;
997
998 /* Preconditions */
999 REQUIRES( isValidObject( objectHandle ) && \
1000 objectHandle >= NO_SYSTEM_OBJECTS );
1001 REQUIRES( objectInfoPtr->type == OBJECT_TYPE_CONTEXT );
1002 REQUIRES( isValidObject( clonedObject ) && \
1003 clonedObject >= NO_SYSTEM_OBJECTS );
1004 REQUIRES( clonedObjectInfoPtr->type == OBJECT_TYPE_CONTEXT );
1005 REQUIRES( objectHandle != clonedObject );
1006 REQUIRES( messageFunction != NULL );
1007
1008 /* Make sure that the original object is in the high state. This will
1009 have been checked by the caller anyway, but we check again here to
1010 make sure */
1011 if( !isInHighState( objectHandle ) )
1012 return( CRYPT_ERROR_NOTINITED );
1013
1014 /* Cloning of non-native contexts is somewhat complex because we usually
1015 can't clone a device object, so we have to detect requests to clone
1016 these objects and increment their reference count instead. This
1017 isn't a major problem because cryptlib always creates native contexts
1018 for clonable algorithms, if the user explicitly overrides this by
1019 using their own device-specific context then the usage will usually
1020 be create, add to envelope, destroy, so there's no need to clone the
1021 context anyway. The only that time there's a potential problem is if
1022 they override the use of native contexts by adding device contexts to
1023 multiple envelopes, but in that case it's assumed that they'll be
1024 aware of potential problems with this approach */
1025 if( objectInfoPtr->dependentDevice != SYSTEM_OBJECT_HANDLE )
1026 return( incRefCount( objectHandle, 0, NULL, TRUE ) );
1027
1028 /* Since this is an internal-use-only object, lock down the action
1029 permissions so that only encryption and hash actions from internal
1030 sources are allowed (assuming they were allowed to begin with).
1031 Keygen is disabled entirely (there should already be a key loaded),
1032 and signing isn't possible with a non-PKC object anyway. This takes
1033 advantage of the ratchet enforced for the action permissions, which
1034 can only make them more restrictive than the existing permissions, to
1035 avoid having to read and modify each permission individually */
1036 actionFlags = \
1037 MK_ACTION_PERM( MESSAGE_CTX_ENCRYPT, ACTION_PERM_NONE_EXTERNAL ) | \
1038 MK_ACTION_PERM( MESSAGE_CTX_DECRYPT, ACTION_PERM_NONE_EXTERNAL ) | \
1039 MK_ACTION_PERM( MESSAGE_CTX_HASH, ACTION_PERM_NONE_EXTERNAL );
1040 status = setPropertyAttribute( clonedObject, CRYPT_IATTRIBUTE_ACTIONPERMS,
1041 &actionFlags );
1042 if( cryptStatusError( status ) )
1043 return( status );
1044
1045 /* Postcondition: The cloned object can only be used internally */
1046 ENSURES( ( clonedObjectInfoPtr->actionFlags & \
1047 ~ACTION_PERM_NONE_EXTERNAL_ALL ) == 0 );
1048
1049 /* Inner precondition: The instance data is valid and ready to be
1050 copied */
1051 assert( isWritePtr( objectInfoPtr->objectPtr, objectInfoPtr->objectSize ) );
1052 assert( isWritePtr( clonedObjectInfoPtr->objectPtr,
1053 clonedObjectInfoPtr->objectSize ) );
1054 REQUIRES( objectInfoPtr->objectSize == clonedObjectInfoPtr->objectSize );
1055
1056 /* Copy across the object contents and reset any instance-specific
1057 information. We only update the owning object if required, in
1058 almost all cases this will be the system device so there's no need
1059 to perform the update */
1060 memcpy( clonedObjectInfoPtr->objectPtr, objectInfoPtr->objectPtr,
1061 objectInfoPtr->objectSize );
1062 messageFunction( clonedObjectInfoPtr->objectPtr, MESSAGE_CHANGENOTIFY,
1063 ( MESSAGE_CAST ) &clonedObject,
1064 MESSAGE_CHANGENOTIFY_OBJHANDLE );
1065 if( objectInfoPtr->owner != clonedObjectInfoPtr->owner )
1066 {
1067 messageFunction( clonedObjectInfoPtr->objectPtr, MESSAGE_CHANGENOTIFY,
1068 &clonedObjectInfoPtr->owner,
1069 MESSAGE_CHANGENOTIFY_OWNERHANDLE );
1070 }
1071
1072 /* We've copied across the object's state, the cloned object is now
1073 initialised ready for use */
1074 clonedObjectInfoPtr->flags |= OBJECT_FLAG_HIGH;
1075
1076 return( CRYPT_OK );
1077 }
1078