cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
cryptusr.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib User Routines *
4 * Copyright Peter Gutmann 1999-2007 *
5 * *
6 ****************************************************************************/
7 
8 /* cryptlib's role-based access control mechanisms are present only for
9  forwards-compatibility with future cryptlib versions that will include
10  role-based access control if there's user demand for it. The following
11  code implements basic user management routines, but the full role-based
12  access control functionality isn't present. Some of the code related to
13  this is therefore present only in template form */
14 
15 #include <stdio.h> /* For sprintf_s() */
16 #include "crypt.h"
17 #ifdef INC_ALL
18  #include "trustmgr.h"
19  #include "user.h"
20 #else
21  #include "cert/trustmgr.h"
22  #include "misc/user.h"
23 #endif /* Compiler-specific includes */
24 
25 /* Default user info. The default user is a special type that has both
26  normal user and SO privileges. This is because in its usual usage mode
27  where cryptlib is functioning as a single-user system the user doesn't
28  know about the existence of user objects and just wants everything to
29  work the way that they expect. Because of this the default user has to
30  be able to perform the full range of available operations, requiring that
31  they appear as both a normal user and an SO.
32 
33  For now the default user is marked as an SO user because the kernel checks
34  don't allow dual-type objects and some operations require that the user be
35  at least an SO user, once a distinction is made between SOs and users this
36  will need to be fixed */
37 
38 static const USER_FILE_INFO FAR_BSS defaultUserInfo = {
39 #if 0 /* 18/05/02 Disabled since ACL checks are messed up by the existence
40  of dual-user roles */
41  CRYPT_USER_NONE, /* Special-case SO+normal user */
42 #else
43  CRYPT_USER_SO, /* Special-case SO user */
44 #endif /* 0 */
45  USER_STATE_USERINITED, /* Initialised, ready for use */
46  "Default cryptlib user", 21, /* Pre-set user name */
47  "<<<<DEFAULT_USER>>>>", "<<<<DEFAULT_USER>>>>",
48  CRYPT_UNUSED /* No corresponding user file */
49  };
50 
51 /****************************************************************************
52 * *
53 * Utility Functions *
54 * *
55 ****************************************************************************/
56 
57 /* Process user-object-specific messages */
58 
60 static int processUserManagement( INOUT USER_INFO *userInfoPtr,
61  STDC_UNUSED void *userMgtInfo,
62  IN_ENUM( MESSAGE_USERMGMT ) \
63  const MESSAGE_USERMGMT_TYPE userMgtType )
64  {
65  assert( isWritePtr( userInfoPtr, sizeof( USER_INFO ) ) );
66 
67  REQUIRES( userMgtType > MESSAGE_USERMGMT_NONE && \
68  userMgtType < MESSAGE_USERMGMT_LAST );
69 
70  switch( userMgtType )
71  {
73  userInfoPtr->flags |= USER_FLAG_ZEROISE;
74  return( CRYPT_OK );
75  }
76 
77  retIntError();
78  }
79 
81 static int processTrustManagement( INOUT USER_INFO *userInfoPtr,
83  IN_ENUM( MESSAGE_TRUSTMGMT ) \
84  const MESSAGE_TRUSTMGMT_TYPE trustMgtType )
85  {
86  int status;
87 
88  assert( isWritePtr( userInfoPtr, sizeof( USER_INFO ) ) );
89  assert( isWritePtr( iCertificate, sizeof( CRYPT_HANDLE ) ) );
90 
91  REQUIRES( trustMgtType > MESSAGE_TRUSTMGMT_NONE && \
92  trustMgtType < MESSAGE_TRUSTMGMT_LAST );
93 
94  switch( trustMgtType )
95  {
97  /* Add the cert to the trust info */
98  status = addTrustEntry( userInfoPtr->trustInfoPtr,
99  *iCertificate, NULL, 0, TRUE );
100  if( cryptStatusError( status ) )
101  return( status );
102  userInfoPtr->trustInfoChanged = TRUE;
103  return( setOption( userInfoPtr->configOptions,
104  userInfoPtr->configOptionsCount,
106 
108  {
109  void *entryToDelete;
110 
111  /* Find the entry to delete and remove it (fides, ut anima, unde
112  abiit eo nunquam redit - Publius Syrus) */
113  if( ( entryToDelete = findTrustEntry( userInfoPtr->trustInfoPtr,
114  *iCertificate, FALSE ) ) == NULL )
115  return( CRYPT_ERROR_NOTFOUND );
116  deleteTrustEntry( userInfoPtr->trustInfoPtr, entryToDelete );
117  userInfoPtr->trustInfoChanged = TRUE;
118  return( setOption( userInfoPtr->configOptions,
119  userInfoPtr->configOptionsCount,
121  }
122 
124  /* Check whether the cert is present in the trusted certs
125  collection */
126  return( ( findTrustEntry( userInfoPtr->trustInfoPtr,
127  *iCertificate, FALSE ) != NULL ) ? \
129 
131  {
132  void *trustedIssuerInfo;
133  int trustedCert;
134 
135  /* Get the trusted issuer of this certificate */
136  trustedIssuerInfo = findTrustEntry( userInfoPtr->trustInfoPtr,
137  *iCertificate, TRUE );
138  if( trustedIssuerInfo == NULL )
139  return( CRYPT_ERROR_NOTFOUND );
140 
141  /* Get the issuer cert and return it to the caller */
142  trustedCert = getTrustedCert( trustedIssuerInfo );
143  if( cryptStatusError( trustedCert ) )
144  return( trustedCert );
145  ENSURES( trustedCert != *iCertificate );
146  *iCertificate = trustedCert;
147 
148  return( CRYPT_OK );
149  }
150  }
151 
152  retIntError();
153  }
154 
155 /****************************************************************************
156 * *
157 * General User Object Functions *
158 * *
159 ****************************************************************************/
160 
161 /* Handle a message sent to a user object */
162 
164 static int userMessageFunction( INOUT TYPECAST( USER_INFO * ) \
165  void *objectInfoPtr,
167  void *messageDataPtr,
168  IN_INT_Z const int messageValue )
169  {
170  USER_INFO *userInfoPtr = ( USER_INFO * ) objectInfoPtr;
171 
172  assert( isWritePtr( objectInfoPtr, sizeof( USER_INFO ) ) );
173 
174  REQUIRES( message > MESSAGE_NONE && message < MESSAGE_LAST );
175  REQUIRES( messageValue >= 0 && messageValue < MAX_INTLENGTH );
176 
177  /* Process destroy object messages */
178  if( message == MESSAGE_DESTROY )
179  {
180  /* Clean up any user-related crypto objects if necessary */
181  if( userInfoPtr->iCryptContext != CRYPT_ERROR )
182  krnlSendNotifier( userInfoPtr->iCryptContext,
184  if( userInfoPtr->iKeyset != CRYPT_ERROR )
186 
187  /* If we're doing a zeroise, clear any persistent user data. It's a
188  bit unclear what to do in case of an error at this point since
189  we're in the middle of a shutdown anyway. We can't really cancel
190  the shutdown because the zeroise fails (what do you do if there's
191  an exception in the exception handler?) so we just have to
192  continue and ignore the failure */
193  if( userInfoPtr->flags & USER_FLAG_ZEROISE )
194  ( void ) zeroiseUsers( userInfoPtr );
195 
196  /* Clean up the trust info and config options */
197  if( userInfoPtr->trustInfoPtr != NULL )
198  endTrustInfo( userInfoPtr->trustInfoPtr );
199  if( userInfoPtr->configOptions != NULL )
200  endOptions( userInfoPtr->configOptions,
201  userInfoPtr->configOptionsCount );
202  if( userInfoPtr->userIndexPtr != NULL )
203  endUserIndex( userInfoPtr->userIndexPtr );
204 
205  return( CRYPT_OK );
206  }
207 
208  /* If we're doing a zeroise, don't process any further messages except a
209  destroy */
210  if( userInfoPtr->flags & USER_FLAG_ZEROISE )
211  return( CRYPT_ERROR_PERMISSION );
212 
213  /* Process attribute get/set/delete messages */
214  if( isAttributeMessage( message ) )
215  {
216  REQUIRES( message == MESSAGE_GETATTRIBUTE || \
217  message == MESSAGE_GETATTRIBUTE_S || \
218  message == MESSAGE_SETATTRIBUTE || \
219  message == MESSAGE_SETATTRIBUTE_S || \
220  message == MESSAGE_DELETEATTRIBUTE );
221  REQUIRES( isAttribute( messageValue ) || \
222  isInternalAttribute( messageValue ) );
223 
224  if( message == MESSAGE_GETATTRIBUTE )
225  return( getUserAttribute( userInfoPtr,
226  ( int * ) messageDataPtr,
227  messageValue ) );
228  if( message == MESSAGE_GETATTRIBUTE_S )
229  return( getUserAttributeS( userInfoPtr,
230  ( MESSAGE_DATA * ) messageDataPtr,
231  messageValue ) );
232  if( message == MESSAGE_SETATTRIBUTE )
233  {
234  /* CRYPT_IATTRIBUTE_INITIALISED is purely a notification message
235  with no parameters so we don't pass it down to the attribute-
236  handling code */
237  if( messageValue == CRYPT_IATTRIBUTE_INITIALISED )
238  {
239  REQUIRES( userInfoPtr->objectHandle == \
241  return( CRYPT_OK );
242  }
243 
244  return( setUserAttribute( userInfoPtr,
245  *( ( int * ) messageDataPtr ),
246  messageValue ) );
247  }
248  if( message == MESSAGE_SETATTRIBUTE_S )
249  {
250  const MESSAGE_DATA *msgData = ( MESSAGE_DATA * ) messageDataPtr;
251 
252  return( setUserAttributeS( userInfoPtr, msgData->data,
253  msgData->length, messageValue ) );
254  }
255  if( message == MESSAGE_DELETEATTRIBUTE )
256  return( deleteUserAttribute( userInfoPtr, messageValue ) );
257 
258  retIntError();
259  }
260 
261  /* Process object-specific messages */
262  if( message == MESSAGE_USER_USERMGMT )
263  return( processUserManagement( userInfoPtr, messageDataPtr,
264  messageValue ) );
265  if( message == MESSAGE_USER_TRUSTMGMT )
266  return( processTrustManagement( userInfoPtr, messageDataPtr,
267  messageValue ) );
268 
269  retIntError();
270  }
271 
272 /* Open a user object. This is a low-level function encapsulated by
273  createUser() and used to manage error exits */
274 
276 static int openUser( OUT_HANDLE_OPT CRYPT_USER *iCryptUser,
278  const USER_FILE_INFO *userInfoTemplate,
279  OUT_OPT_PTR USER_INFO **userInfoPtrPtr )
280  {
281  USER_INFO *userInfoPtr;
282  USER_FILE_INFO *userFileInfo;
283  static const MAP_TABLE subtypeMapTbl[] = {
288  };
289  OBJECT_SUBTYPE subType;
290  int value, status;
291 
292  assert( isWritePtr( iCryptUser, sizeof( CRYPT_USER * ) ) );
293  assert( isReadPtr( userInfoTemplate, sizeof( USER_FILE_INFO ) ) );
294  assert( isWritePtr( userInfoPtrPtr, sizeof( USER_INFO * ) ) );
295 
296  REQUIRES( ( iCryptOwner == SYSTEM_OBJECT_HANDLE ) || \
297  ( iCryptOwner == DEFAULTUSER_OBJECT_HANDLE ) || \
298  isHandleRangeValid( iCryptOwner ) );
299 
300  /* The default user is a special type that has both normal user and SO
301  privileges. This is because in its usual usage mode where cryptlib
302  is functioning as a single-user system the user doesn't know about
303  the existence of user objects and just wants everything to work the
304  way that they expect. Because of this the default user has to be
305  able to perform the full range of available operations, requiring
306  that they appear as both a normal user and an SO */
307 #if 0 /* 18/05/02 Disabled since ACL checks are messed up by the existence
308  of dual-user roles */
309  assert( userInfoTemplate->type == CRYPT_USER_NORMAL || \
310  userInfoTemplate->type == CRYPT_USER_SO || \
311  userInfoTemplate->type == CRYPT_USER_CA || \
312  ( userInfoTemplate->type == CRYPT_USER_NONE && \
313  userInfoTemplate->userNameLength == \
314  defaultUserInfo.userNameLength && \
315  !memcmp( userInfoTemplate->userName, defaultUserInfo.userName,
316  defaultUserInfo.userNameLength ) ) );
317 #endif /* 0 */
318 
319  /* Clear return values */
320  *iCryptUser = CRYPT_ERROR;
321  *userInfoPtrPtr = NULL;
322 
323  /* Create the user object */
324  status = mapValue( userInfoTemplate->type, &value, subtypeMapTbl,
325  FAILSAFE_ARRAYSIZE( subtypeMapTbl, MAP_TABLE ) );
326  ENSURES( cryptStatusOK( status ) );
327  subType = value;
328  status = krnlCreateObject( iCryptUser, ( void ** ) &userInfoPtr,
329  sizeof( USER_INFO ), OBJECT_TYPE_USER,
330  subType, CREATEOBJECT_FLAG_NONE, iCryptOwner,
331  ACTION_PERM_NONE_ALL, userMessageFunction );
332  if( cryptStatusError( status ) )
333  return( status );
334  ANALYSER_HINT( userInfoPtr != NULL );
335  *userInfoPtrPtr = userInfoPtr;
336  userInfoPtr->objectHandle = *iCryptUser;
337  userFileInfo = &userInfoPtr->userFileInfo;
338  userFileInfo->type = userInfoTemplate->type;
339  userFileInfo->state = userInfoTemplate->state;
340  userFileInfo->fileRef = userInfoTemplate->fileRef;
341  memcpy( userFileInfo->userName, userInfoTemplate->userName,
342  userInfoTemplate->userNameLength );
343  userFileInfo->userNameLength = userInfoTemplate->userNameLength;
344  memcpy( userFileInfo->userID, userInfoTemplate->userID, KEYID_SIZE );
345  memcpy( userFileInfo->creatorID, userInfoTemplate->creatorID, KEYID_SIZE );
346 
347  /* Set up any internal objects to contain invalid handles */
348  userInfoPtr->iKeyset = userInfoPtr->iCryptContext = CRYPT_ERROR;
349 
350  /* Initialise the config options and trust info */
351  status = initTrustInfo( &userInfoPtr->trustInfoPtr );
352  if( cryptStatusOK( status ) )
353  status = initOptions( &userInfoPtr->configOptions,
354  &userInfoPtr->configOptionsCount );
355  return( status );
356  }
357 
359 int createUser( INOUT MESSAGE_CREATEOBJECT_INFO *createInfo,
360  STDC_UNUSED const void *auxDataPtr,
361  STDC_UNUSED const int auxValue )
362  {
363  CRYPT_USER iCryptUser;
364  USER_INFO *userInfoPtr;
365  char userFileName[ 16 + 8 ];
366  int fileRef, initStatus, status;
367 
368  assert( isWritePtr( createInfo, sizeof( MESSAGE_CREATEOBJECT_INFO ) ) );
369 
370  REQUIRES( auxDataPtr == NULL && auxValue == 0 );
371  REQUIRES( createInfo->strArgLen1 >= MIN_NAME_LENGTH && \
372  createInfo->strArgLen1 <= CRYPT_MAX_TEXTSIZE );
373  REQUIRES( createInfo->strArgLen2 >= MIN_NAME_LENGTH && \
374  createInfo->strArgLen2 <= CRYPT_MAX_TEXTSIZE );
375 
376  /* We can't create another user object with the same name as the
377  cryptlib default user (actually we could and nothing bad would happen,
378  but we reserve the use of this name just in case) */
379  if( createInfo->strArgLen1 == defaultUserInfo.userNameLength && \
380  !strCompare( createInfo->strArg1, defaultUserInfo.userName,
381  defaultUserInfo.userNameLength ) )
382  return( CRYPT_ERROR_INITED );
383 
385 /* Problem: Access to any user info is via the root user object, however */
386 /* we don't have access to it at this point. Pass it in as auxDataPtr? */
387 /* Need to differentiate cryptCreateUser() vs. cryptLogin(), login uses */
388 /* the default user object as its target? This is complex, we really */
389 /* need to target the message at the default user to get access to the user */
390 /* info index, but then it won't go through cryptdev's create-object- */
391 /* handling any more */
393 #if 0
394  /* Find the user information for the given user */
395  status = fileRef = findUserIndexEntry( USERID_NAME, createInfo->strArg1,
396  createInfo->strArgLen1 );
397  if( cryptStatusError( status ) )
398  {
399  /* If we get a special-case OK status, we're in the zeroised state
400  with no user info present, make sure that the user is logging in
401  with the default SO password */
402  if( status == OK_SPECIAL )
403  status = ( isZeroisePassword( createInfo->strArg2, \
404  createInfo->strArgLen2 ) ) ? \
406  if( cryptStatusError( status ) )
407  return( status );
408  fileRef = -1; /* No user file present yet for primary SO */
409 
410  /* We're logging in as the primary SO with the SO default password,
411  create the primary SO user object */
412  assert( isZeroisePassword( createInfo->strArg2, \
413  createInfo->strArgLen2 ) );
414  initStatus = openUser( &iCryptUser, createInfo->cryptOwner,
415  getPrimarySoUserInfo(), &userInfoPtr );
416  }
417  else
418  {
419  USER_FILE_INFO userFileInfo;
420 
421  /* We're in the non-zeroised state, no user can use the default SO
422  password */
423  if( isZeroisePassword( createInfo->strArg2, createInfo->strArgLen2 ) )
424  return( CRYPT_ERROR_WRONGKEY );
425 
426  /* Read the user info from the user file and perform access
427  verification */
428  status = getCheckUserInfo( &userFileInfo, fileRef );
429  if( cryptStatusError( status ) )
430  return( status );
431 
432  /* Pass the call on to the lower-level open function */
433  assert( createInfo->strArgLen1 == userFileInfo.userNameLength && \
434  !memcmp( createInfo->strArg1, userFileInfo.userName,
435  userFileInfo.userNameLength ) );
436  initStatus = openUser( &iCryptUser, createInfo->cryptOwner,
437  &userFileInfo, &userInfoPtr );
438  zeroise( &userFileInfo, sizeof( USER_FILE_INFO ) );
439  }
440 #endif
441 
442 { /* Get rid of compiler warnings */
443 userInfoPtr = NULL;
444 initStatus = CRYPT_ERROR_FAILED;
445 iCryptUser = CRYPT_UNUSED;
446 fileRef = 0;
447 }
448  if( cryptStatusError( initStatus ) )
449  {
450  /* If the create object failed, return immediately */
451  if( userInfoPtr == NULL )
452  return( initStatus );
453 
454  /* The init failed, make sure that the object gets destroyed when we
455  notify the kernel that the setup process is complete */
456  krnlSendNotifier( iCryptUser, IMESSAGE_DESTROY );
457  }
458 
459  /* We've finished setting up the object-type-specific info, tell the
460  kernel that the object is ready for use */
461  status = krnlSendMessage( iCryptUser, IMESSAGE_SETATTRIBUTE,
462  MESSAGE_VALUE_OK, CRYPT_IATTRIBUTE_STATUS );
463  if( cryptStatusError( initStatus ) || cryptStatusError( status ) )
464  return( cryptStatusError( initStatus ) ? initStatus : status );
465 
466  /* If the user object has a corresponding user info file, read any
467  stored config options into the object. We have to do this after
468  it's initialised because the config data, coming from an external
469  (and therefore untrusted) source has to go through the kernel's
470  ACL checking */
471  if( fileRef >= 0 )
472  {
473  sprintf_s( userFileName, 16, "u%06x", fileRef );
474  status = readConfig( iCryptUser, userFileName,
475  userInfoPtr->trustInfoPtr );
476  if( cryptStatusError( status ) )
477  {
478  /* The config data read failed, we can't create the user
479  object that uses it */
480  krnlSendNotifier( iCryptUser, IMESSAGE_DESTROY );
481  return( status );
482  }
483  }
484  createInfo->cryptHandle = iCryptUser;
485  return( CRYPT_OK );
486  }
487 
488 /* Create the default user object */
489 
490 CHECK_RETVAL \
491 static int createDefaultUserObject( void )
492  {
493  CRYPT_USER iUserObject;
494  USER_INFO *userInfoPtr;
495  int initStatus, status;
496 
497  /* Pass the call on to the lower-level open function. This user is
498  unique and has no owner or type.
499 
500  Normally if an object init fails we tell the kernel to destroy it by
501  sending it a destroy message, which is processed after the object's
502  status has been set to normal. However we don't have the privileges
503  to do this for the default user object (or the system object) so we
504  just pass the error code back to the caller, which causes the
505  cryptlib init to fail.
506 
507  In addition the init can fail in one of two ways, either the object
508  isn't even created (deviceInfoPtr == NULL, nothing to clean up), in
509  which case we bail out immediately, or the object is created but wasn't
510  set up properly (deviceInfoPtr is allocated, but the object can't be
511  used) in which case we bail out after we update its status */
512  initStatus = openUser( &iUserObject, SYSTEM_OBJECT_HANDLE, &defaultUserInfo,
513  &userInfoPtr );
514  if( cryptStatusError( initStatus ) )
515  {
516  /* If the create object failed, return immediately */
517  if( userInfoPtr == NULL )
518  return( initStatus );
519  }
520  ENSURES( iUserObject == DEFAULTUSER_OBJECT_HANDLE );
521  if( cryptStatusOK( initStatus ) )
522  {
523  /* Read the user index. We make this part of the object init because
524  it's used for access control, unlike the config option read where
525  we can fall back to defaults if there's a problem this one is
526  critical enough that we abort the cryptlib init if it fails */
527  initStatus = initUserIndex( &userInfoPtr->userIndexPtr );
528  }
529 
530  /* We've finished setting up the object-type-specific info, tell the
531  kernel that the object is ready for use */
532  status = krnlSendMessage( iUserObject, IMESSAGE_SETATTRIBUTE,
533  MESSAGE_VALUE_OK, CRYPT_IATTRIBUTE_STATUS );
534  if( cryptStatusError( initStatus ) || cryptStatusError( status ) )
535  return( cryptStatusError( initStatus ) ? initStatus : status );
536 
537  /* Read any stored config options into the object. We have to do this
538  after it's initialised because the config data, coming from an
539  external (and therefore untrusted) source has to go through the
540  kernel's ACL checking.
541 
542  What to do in case of an error reading the config file is a bit
543  problematic, we don't want to cause whatever application is using
544  cryptlib to abort mysteriously just because a bit in some config file
545  that most people don't even know exists got flipped, so we treat the
546  read as an opportunistic read and fall back to built-in safe defaults
547  if there's a problem, warning the user in debug mode */
548  status = readConfig( iUserObject, "cryptlib", userInfoPtr->trustInfoPtr );
549  if( cryptStatusError( status ) )
550  {
551  DEBUG_DIAG(( "Couldn't read config data, using default config" ));
552  assert( DEBUG_WARN );
553  DEBUG_PRINT(( "Configuration file read failed with status %d.\n",
554  status ));
555  }
556 
557  /* The object has been initialised, move it into the initialised state */
558  return( krnlSendMessage( iUserObject, IMESSAGE_SETATTRIBUTE,
560  CRYPT_IATTRIBUTE_INITIALISED ) );
561  }
562 
563 /* Generic management function for this class of object */
564 
565 CHECK_RETVAL \
566 int userManagementFunction( IN_ENUM( MANAGEMENT_ACTION ) \
567  const MANAGEMENT_ACTION_TYPE action )
568  {
569  int status;
570 
571  REQUIRES( action == MANAGEMENT_ACTION_INIT );
572 
573  switch( action )
574  {
576  status = createDefaultUserObject();
577  if( cryptStatusError( status ) )
578  {
579  DEBUG_DIAG(( "User object creation failed" ));
580  }
581  return( status );
582  }
583 
584  retIntError();
585  }