cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
user.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib User Routines *
4 * Copyright Peter Gutmann 1999-2007 *
5 * *
6 ****************************************************************************/
7 
8 #include <stdio.h> /* For snprintf_s() */
9 #include "crypt.h"
10 #ifdef INC_ALL
11  #include "asn1.h"
12  #include "user.h"
13 #else
14  #include "enc_dec/asn1.h"
15  #include "misc/user.h"
16 #endif /* Compiler-specific includes */
17 
18 /* The different types of userID that we can use to look up users in the
19  index */
20 
21 typedef enum {
22  USERID_NONE, /* No userID type */
23  USERID_USERID, /* User's userID */
24  USERID_CREATORID, /* Creating SO's userID */
25  USERID_NAME, /* User's name */
26  USERID_LAST /* Last possible userID type */
27  } USERID_TYPE;
28 
29 /* cryptlib can work with multiple users (although it's extremely unlikely
30  that there'll ever be more than one or two), we allow a maximum of
31  MAX_USER_OBJECTS in order to discourage them from being used as a
32  substitute for OS user management. A setting of 32 objects consumes
33  ~4K of memory (32 x ~128), so we choose that as the limit */
34 
35 #ifdef CONFIG_CONSERVE_MEMORY
36  #define MAX_USER_OBJECTS 4
37 #else
38  #define MAX_USER_OBJECTS 32
39 #endif /* CONFIG_CONSERVE_MEMORY */
40 
41 /* The size of the default buffer used to read data from a keyset. If
42  the data is larger than this, the buffer is allocated dynamically */
43 
44 #define USERDATA_BUFFERSIZE 1024
45 
46 /* The maximum size of the encoded index data */
47 
48 #define MAX_USERINDEX_SIZE ( ( 16 + ( KEYID_SIZE * 2 ) + \
49  CRYPT_MAX_TEXTSIZE + 8 ) * MAX_USER_OBJECTS )
50 
51 /* Primary SO user info */
52 
53 static const USER_FILE_INFO FAR_BSS primarySOInfo = {
54  CRYPT_USER_SO, /* SO user */
55  USER_STATE_SOINITED, /* SO initialised, not ready for use */
56  "Security officer", 16, /* Pre-set user name */
57  "<<<PRIMARYSO_USER>>>", "<<<TETRAGRAMMATON>>>",
58  -1 /* No user file when starting from zeroised state */
59  };
60 
61 /* The primary SO password after zeroisation */
62 
63 #define PRIMARYSO_PASSWORD "zeroised"
64 #define PRIMARYSO_ALTPASSWORD "zeroized"
65 #define PRIMARYSO_PASSWORD_LENGTH 8
66 
67 /* The structure that stores the user index in the default user object */
68 
69 typedef struct {
70  USER_FILE_INFO userIndex[ MAX_USER_OBJECTS ]; /* User index */
71  int lastEntry; /* Last entry in user index */
73 
74 /****************************************************************************
75 * *
76 * Utility Functions *
77 * *
78 ****************************************************************************/
79 
80 /* Open a user or index keyset */
81 
83 static int openKeyset( OUT_HANDLE_OPT CRYPT_KEYSET *iKeyset,
84  IN_BUFFER( fileNameLen ) const char *fileName,
85  IN_LENGTH_SHORT const int fileNameLen,
86  IN_ENUM_OPT( CRYPT_KEYOPT ) const int options )
87  {
88  MESSAGE_CREATEOBJECT_INFO createInfo;
89  char userFilePath[ MAX_PATH_LENGTH + 8 ];
90  int userFilePathLen, status;
91 
92  assert( isWritePtr( iKeyset, sizeof( CRYPT_KEYSET ) ) );
93  assert( isReadPtr( fileName, fileNameLen ) );
94 
95  REQUIRES( fileNameLen > 0 && fileNameLen < MAX_INTLENGTH_SHORT );
96  REQUIRES( options >= CRYPT_KEYOPT_NONE && options < CRYPT_KEYOPT_LAST );
97 
98  /* Clear return value */
99  *iKeyset = CRYPT_ERROR;
100 
101  /* Open the given keyset */
102  status = fileBuildCryptlibPath( userFilePath, MAX_PATH_LENGTH,
103  &userFilePathLen, fileName, fileNameLen,
104  ( options == CRYPT_KEYOPT_CREATE ) ? \
106  if( cryptStatusError( status ) )
107  {
108  /* Map the lower-level filesystem-specific error into a more
109  meaningful generic error */
110  return( CRYPT_ERROR_OPEN );
111  }
113  createInfo.arg2 = options;
114  createInfo.strArg1 = userFilePath;
115  createInfo.strArgLen1 = userFilePathLen;
117  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
119  if( cryptStatusOK( status ) )
120  *iKeyset = createInfo.cryptHandle;
121  return( status );
122  }
123 
125 static int openUserKeyset( OUT_HANDLE_OPT CRYPT_KEYSET *iUserKeyset,
126  IN_INT_SHORT_Z const int fileRef,
127  IN_ENUM_OPT( CRYPT_KEYOPT ) const int options )
128  {
129  char userFileName[ 16 + 8 ];
130  int userFileNameLen;
131 
132  assert( isWritePtr( iUserKeyset, sizeof( CRYPT_KEYSET ) ) );
133 
134  REQUIRES( fileRef >= 0 && fileRef < MAX_INTLENGTH_SHORT );
135  REQUIRES( options >= CRYPT_KEYOPT_NONE && options < CRYPT_KEYOPT_LAST );
136 
137  userFileNameLen = sprintf_s( userFileName, 16, "u%06x", fileRef );
138  return( openKeyset( iUserKeyset, userFileName, userFileNameLen,
139  options ) );
140  }
141 
143 static int openIndexKeyset( OUT CRYPT_KEYSET *iIndexKeyset,
144  IN_ENUM_OPT( CRYPT_KEYOPT ) const int options )
145  {
146  assert( isWritePtr( iIndexKeyset, sizeof( CRYPT_KEYSET ) ) );
147 
148  REQUIRES( options >= CRYPT_KEYOPT_NONE && options < CRYPT_KEYOPT_LAST );
149 
150  return( openKeyset( iIndexKeyset, "index", 5, options ) );
151  }
152 
153 /* Add a user key to the keyset */
154 
156 static int addKey( IN_HANDLE const CRYPT_KEYSET iUserKeyset,
158  IN_BUFFER( userIdLength ) const void *userID,
159  IN_LENGTH_SHORT const int userIdLength,
160  IN_BUFFER( passwordLength ) const char *password,
162  const BOOLEAN isPrivateKey )
163  {
164  MESSAGE_KEYMGMT_INFO setkeyInfo;
166  int status;
167 
168  assert( isReadPtr( userID, userIdLength ) );
169  assert( isReadPtr( password, passwordLength ) );
170 
171  REQUIRES( isHandleRangeValid( iUserKeyset ) );
172  REQUIRES( isHandleRangeValid( iCryptContext ) );
173  REQUIRES( userIdLength > 0 && userIdLength < MAX_INTLENGTH_SHORT );
174  REQUIRES( passwordLength > 0 && passwordLength < MAX_INTLENGTH_SHORT );
175 
176  setMessageData( &msgData, ( MESSAGE_CAST ) userID, userIdLength );
177  status = krnlSendMessage( iUserKeyset, IMESSAGE_SETATTRIBUTE_S,
178  &msgData, CRYPT_IATTRIBUTE_USERID );
179  if( cryptStatusError( status ) )
180  return( status );
181 
182  setMessageKeymgmtInfo( &setkeyInfo, CRYPT_KEYID_NONE, NULL, 0,
183  ( MESSAGE_CAST ) password, passwordLength,
185  setkeyInfo.cryptHandle = iCryptContext;
186  status = krnlSendMessage( iUserKeyset, IMESSAGE_KEY_SETKEY,
187  &setkeyInfo, isPrivateKey ? \
190  return( status );
191  }
192 
193 /****************************************************************************
194 * *
195 * Manage User Index *
196 * *
197 ****************************************************************************/
198 
199 /* Find a user in the user index. Note that this search implements a flat
200  namespace rather than allowing duplicate names created by different SOs
201  because when we're looking up a user we don't know which SO they belong
202  to until after we've looked them up */
203 
205 static const USER_FILE_INFO *findUser( IN_ARRAY( noUserIndexEntries ) \
206  const USER_FILE_INFO *userIndex,
207  IN_RANGE( 1, MAX_USER_OBJECTS ) \
208  const int noUserIndexEntries,
209  IN_ENUM( USERID ) const USERID_TYPE idType,
210  IN_BUFFER( idLength ) const BYTE *id,
211  IN_LENGTH_SHORT const int idLength )
212  {
213  int i, iterationCount;
214 
215  assert( isReadPtr( userIndex, \
216  sizeof( USER_FILE_INFO ) * noUserIndexEntries ) );
217  assert( isReadPtr( id, idLength ) );
218 
219  REQUIRES_N( noUserIndexEntries > 0 && \
220  noUserIndexEntries <= MAX_USER_OBJECTS );
221  REQUIRES_N( idType > USERID_NONE && idType < USERID_LAST );
222  REQUIRES_N( idLength > 0 && idLength < MAX_INTLENGTH_SHORT );
223 
224  for( i = 0, iterationCount = 0;
225  i < noUserIndexEntries && \
226  iterationCount < FAILSAFE_ITERATIONS_LARGE;
227  i++, iterationCount++ )
228  {
229  const USER_FILE_INFO *userIndexPtr = &userIndex[ i ];
230 
231  switch( idType )
232  {
233  case USERID_USERID:
234  if( idLength == KEYID_SIZE && \
235  !memcmp( userIndexPtr->userID, id, idLength ) )
236  return( userIndexPtr );
237  break;
238 
239  case USERID_CREATORID:
240  if( idLength == KEYID_SIZE && \
241  !memcmp( userIndexPtr->creatorID, id, idLength ) )
242  return( userIndexPtr );
243  break;
244 
245  case USERID_NAME:
246  if( idLength == userIndexPtr->userNameLength && \
247  !memcmp( userIndexPtr->userName, id, idLength ) )
248  return( userIndexPtr );
249  break;
250 
251  default:
253  }
254  }
255  ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_LARGE );
256 
257  return( NULL );
258  }
259 
260 /* Find a free user entry */
261 
263 static USER_FILE_INFO *findFreeEntry( IN_ARRAY( noUserIndexEntries ) \
264  USER_FILE_INFO *userIndex,
265  IN_RANGE( 1, MAX_USER_OBJECTS ) \
266  const int noUserIndexEntries,
267  OUT_INT_SHORT_Z int *fileRef )
268  {
269  USER_FILE_INFO *userIndexPtr;
270  int newFileRef, i, iterationCount;
271 
272  assert( isWritePtr( userIndex, \
273  sizeof( USER_FILE_INFO ) * noUserIndexEntries ) );
274  assert( isWritePtr( fileRef, sizeof( int ) ) );
275 
276  REQUIRES_N( noUserIndexEntries > 0 && \
277  noUserIndexEntries <= MAX_USER_OBJECTS );
278 
279  /* Look for an available free entry */
280  for( i = 0, iterationCount = 0;
281  i < noUserIndexEntries && \
282  iterationCount < FAILSAFE_ITERATIONS_LARGE;
283  i++, iterationCount++ )
284  {
285  if( userIndex[ i ].state == USER_STATE_NONE )
286  break;
287  }
288  ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_LARGE );
289  if( i >= noUserIndexEntries )
290  {
291  /* No more available entries */
292  *fileRef = CRYPT_ERROR;
293  return( NULL );
294  }
295 
296  /* Remember where we found our match */
297  userIndexPtr = &userIndex[ i ];
298 
299  /* We've found a free entry, now look for an unused fileRef. There are
300  two possible strategies for this, the first is to make it generational
301  and always allocate a new fileRef, the second is to use the smallest
302  available value, i.e. to re-use values. The former has problems with
303  overflow (although it'd have to be a pretty funny situation to cause
304  this), the latter has potential problems with user confusion when one
305  ref #3 user file is replaced by another ref #3 file that belongs to
306  a completely different user. However, even the generational approach
307  has problems (unless we can make the last-used fileRef persistent)
308  because deleting the highest-numbered ref. and then creating a new one
309  will result in the fileRef being re-allocated to the newly-created
310  file.
311 
312  Since this is all highly speculative (it's not certain under what
313  conditions we could run into these problems because users aren't
314  expected to be bypassing cryptlib to directly access the user files),
315  we take the simplest approach and use the lowest-value free fileRef.
316  This is somewhat ugly because it's potentially an O( n^2 ) operation,
317  but the actualy impact is insignificant because the number of users
318  is tiny and new user creation is extremely rare, so it's not worth
319  switching to the complexity of a more sophisticated algorithm */
320  for( newFileRef = 0; newFileRef < MAX_USER_OBJECTS; newFileRef++ )
321  {
322  /* Check whether this fileRef is already in use. If not, we're
323  done */
324  for( i = 0; i < noUserIndexEntries; i++ )
325  {
326  if( userIndex[ i ].fileRef == newFileRef )
327  break;
328  }
329  if( i >= MAX_USER_OBJECTS )
330  break;
331  }
332  ENSURES_N( newFileRef < MAX_USER_OBJECTS );
333  *fileRef = newFileRef;
334 
335  return( userIndexPtr );
336  }
337 
339 static int createUserEntry( OUT_OPT_PTR USER_FILE_INFO **userIndexPtrPtr,
340  IN_ARRAY( noUserIndexEntries ) \
341  USER_FILE_INFO *userIndex,
342  IN_RANGE( 1, MAX_USER_OBJECTS ) \
343  const int noUserIndexEntries,
344  INOUT USER_FILE_INFO *userFileInfo )
345  {
346  USER_FILE_INFO *userIndexPtr;
347  int fileRef, iterationCount, status = CRYPT_OK;
348 
349  assert( isWritePtr( userIndexPtrPtr, sizeof( USER_FILE_INFO * ) ) );
350  assert( isWritePtr( userIndex, \
351  sizeof( USER_FILE_INFO ) * noUserIndexEntries ) );
352  assert( isWritePtr( userFileInfo, sizeof( USER_FILE_INFO ) ) );
353 
354  REQUIRES( noUserIndexEntries > 0 && \
355  noUserIndexEntries <= MAX_USER_OBJECTS );
356 
357  /* Clear return value */
358  *userIndexPtrPtr = NULL;
359 
360  /* Check whether this user is already present in the index */
361  if( findUser( userIndex, noUserIndexEntries, USERID_NAME,
362  userFileInfo->userName, userFileInfo->userNameLength ) != NULL )
363  return( CRYPT_ERROR_DUPLICATE );
364 
365  /* Make sure that the userID that we're using is unique. This is a
366  pretty straightforward operation, we just keep generating new random
367  IDs until we get one that's not already present */
368  for( iterationCount = 0;
369  !cryptStatusError( status ) && \
370  iterationCount < FAILSAFE_ITERATIONS_LARGE;
371  iterationCount++ )
372  {
373  if( findUser( userIndex, noUserIndexEntries, USERID_USERID,
374  userFileInfo->userID, KEYID_SIZE ) != NULL )
375  {
377 
378  setMessageData( &msgData, ( MESSAGE_CAST ) userFileInfo->userID,
379  KEYID_SIZE );
381  IMESSAGE_GETATTRIBUTE_S, &msgData,
382  CRYPT_IATTRIBUTE_RANDOM_NONCE );
383  }
384  }
385  ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
386 
387  /* Locate a new unused entry that we can use */
388  userIndexPtr = findFreeEntry( userIndex, MAX_USER_OBJECTS, &fileRef );
389  if( userIndexPtr == NULL )
390  return( CRYPT_ERROR_OVERFLOW );
391  userFileInfo->fileRef = fileRef;
392 
393  return( CRYPT_OK );
394  }
395 
396 /* Read the user index file:
397 
398  UserIndexEntry ::= SEQUENCE {
399  iD OCTET STRING SIZE(16), -- User ID
400  creatorID OCTET STRING SIZE(16), -- Creating SO's ID
401  name UTF8String, -- User name
402  fileReference INTEGER -- Reference to user file
403  } */
404 
405 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
406 static int readIndexEntry( INOUT STREAM *stream,
407  INOUT USER_FILE_INFO *userIndexPtr )
408  {
409  USER_FILE_INFO userIndexEntry;
410  long value;
411  int length, status;
412 
413  assert( isWritePtr( stream, sizeof( STREAM ) ) );
414  assert( isWritePtr( userIndexPtr, sizeof( USER_FILE_INFO ) ) );
415 
416  /* Clear return value */
417  memset( userIndexPtr, 0, sizeof( USER_FILE_INFO ) );
418 
419  /* Read the user index data */
420  memset( &userIndexEntry, 0, sizeof( USER_FILE_INFO ) );
421  readSequence( stream, NULL );
422  readOctetString( stream, userIndexEntry.userID, &length, KEYID_SIZE,
423  KEYID_SIZE );
424  readOctetString( stream, userIndexEntry.creatorID, &length, KEYID_SIZE,
425  KEYID_SIZE );
426  readCharacterString( stream, userIndexEntry.userName,
427  CRYPT_MAX_TEXTSIZE, &userIndexEntry.userNameLength,
428  BER_STRING_UTF8 );
429  status = readShortInteger( stream, &value );
430  if( cryptStatusError( status ) )
431  return( status );
432  userIndexEntry.fileRef = value;
433 
434  /* Return the result to the caller */
435  memcpy( userIndexPtr, &userIndexEntry, sizeof( USER_FILE_INFO ) );
436  return( CRYPT_OK );
437  }
438 
440 static int readIndex( IN_HANDLE const CRYPT_KEYSET iIndexKeyset,
441  IN_ARRAY( maxUserObjects ) USER_FILE_INFO *userIndex,
442  IN_RANGE( 1, MAX_USER_OBJECTS ) const int maxUserObjects )
443  {
444  STREAM stream;
445  DYNBUF userIndexDB;
446  int i, iterationCount, status;
447 
448  assert( isWritePtr( userIndex, \
449  maxUserObjects * sizeof( USER_FILE_INFO ) ) );
450 
451  REQUIRES( isHandleRangeValid( iIndexKeyset ) );
452  REQUIRES( maxUserObjects > 0 && maxUserObjects <= MAX_USER_OBJECTS );
453 
454  /* Read the user index file into memory */
455  status = dynCreate( &userIndexDB, iIndexKeyset,
456  CRYPT_IATTRIBUTE_USERINDEX );
457  if( cryptStatusError( status ) )
458  return( status );
459  sMemConnect( &stream, dynData( userIndexDB ), dynLength( userIndexDB ) );
460  for( i = 0, iterationCount = 0;
461  cryptStatusOK( status ) && \
462  stell( &stream ) < dynLength( userIndexDB ) && \
463  i < maxUserObjects && iterationCount < FAILSAFE_ITERATIONS_LARGE;
464  i++, iterationCount++ )
465  {
466  status = readIndexEntry( &stream, &userIndex[ i ] );
467  }
468  ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
469  sMemDisconnect( &stream );
470  dynDestroy( &userIndexDB );
471  if( cryptStatusError( status ) )
472  return( status );
473  if( i > maxUserObjects )
474  return( CRYPT_ERROR_OVERFLOW );
475 
476  return( i );
477  }
478 
479 /* Write the user index file */
480 
481 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
482 static int writeUserIndexEntry( INOUT STREAM *stream,
483  const USER_FILE_INFO *userIndexPtr )
484  {
485  assert( isWritePtr( stream, sizeof( STREAM ) ) );
486  assert( isReadPtr( userIndexPtr, sizeof( USER_FILE_INFO ) ) );
487 
488  writeSequence( stream, 2 * sizeofObject( KEYID_SIZE ) + \
489  sizeofObject( userIndexPtr->userNameLength ) + \
490  sizeofShortInteger( userIndexPtr->fileRef) );
491  writeOctetString( stream, userIndexPtr->userID, KEYID_SIZE, DEFAULT_TAG );
492  writeOctetString( stream, userIndexPtr->creatorID, KEYID_SIZE, DEFAULT_TAG );
493  writeCharacterString( stream, userIndexPtr->userName,
494  userIndexPtr->userNameLength, BER_STRING_UTF8 );
495  return( writeShortInteger( stream, userIndexPtr->fileRef, DEFAULT_TAG ) );
496  }
497 
499 static int writeUserIndex( IN_HANDLE const CRYPT_KEYSET iIndexKeyset,
500  IN_ARRAY( noUserIndexEntries ) \
501  USER_FILE_INFO *userIndex,
502  IN_RANGE( 1, MAX_USER_OBJECTS ) \
503  const int noUserIndexEntries )
504  {
505  STREAM stream;
507  BYTE userIndexData[ MAX_USERINDEX_SIZE + 8 ];
508  int userIndexDataLength, i, iterationCount, status = CRYPT_OK;
509 
510  assert( isWritePtr( userIndex, \
511  noUserIndexEntries * sizeof( USER_FILE_INFO ) ) );
512 
513  REQUIRES( isHandleRangeValid( iIndexKeyset ) );
514  REQUIRES( noUserIndexEntries > 0 && \
515  noUserIndexEntries <= MAX_USER_OBJECTS );
516 
517  /* Write the user index data to a buffer so that we can send it to the
518  index keyset */
519  sMemOpen( &stream, userIndexData, MAX_USERINDEX_SIZE );
520  for( i = 0, iterationCount = 0;
521  i < noUserIndexEntries && cryptStatusOK( status ) && \
522  iterationCount < FAILSAFE_ITERATIONS_LARGE;
523  i++, iterationCount++ )
524  {
525  if( userIndex[ i ].state != USER_STATE_NONE )
526  status = writeUserIndexEntry( &stream, &userIndex[ i ] );
527  }
528  ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
529  userIndexDataLength = stell( &stream );
530  sMemDisconnect( &stream );
531  if( cryptStatusError( status ) )
532  return( status );
533 
534  /* Write the user index data to the keyset */
535  setMessageData( &msgData, userIndexData, userIndexDataLength );
536  return( krnlSendMessage( iIndexKeyset, IMESSAGE_SETATTRIBUTE_S,
537  &msgData, CRYPT_IATTRIBUTE_USERINDEX ) );
538  }
539 
540 /****************************************************************************
541 * *
542 * Read/Write User Data *
543 * *
544 ****************************************************************************/
545 
546 /* Read/write user data:
547 
548  UserInfo ::= SEQUENCE {
549  role ENUMERATED, -- SO/user/CA
550  iD OCTET STRING SIZE(16), -- User ID
551  creatorID OCTET STRING SIZE(16), -- Creating SO's ID
552  name UTF8String, -- User name
553  } */
554 
555 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
556 static int readUserData( INOUT USER_FILE_INFO *userFileInfoPtr,
557  IN_BUFFER( userDataLength ) const void *userData,
558  IN_LENGTH_SHORT const int userDataLength )
559  {
560  STREAM stream;
561  int enumValue, length, status;
562 
563  assert( isWritePtr( userFileInfoPtr, sizeof( USER_FILE_INFO ) ) );
564  assert( isReadPtr( userData, userDataLength ) );
565 
566  REQUIRES( userDataLength > 0 && userDataLength < MAX_INTLENGTH_SHORT );
567 
568  /* Clear return value */
569  memset( userFileInfoPtr, 0, sizeof( USER_FILE_INFO ) );
570 
571  /* Read the user info */
572  sMemConnect( &stream, userData, userDataLength );
573  readSequence( &stream, NULL );
574  readEnumerated( &stream, &enumValue );
575  userFileInfoPtr->type = enumValue;
576  readOctetString( &stream, userFileInfoPtr->userID, &length,
578  readOctetString( &stream, userFileInfoPtr->creatorID, &length,
580  status = readCharacterString( &stream, userFileInfoPtr->userName,
582  &userFileInfoPtr->userNameLength,
583  BER_STRING_UTF8 );
584  sMemDisconnect( &stream );
585 
586  return( status );
587  }
588 
590 static int writeUserData( OUT_BUFFER( userDataMaxLength, \
591  *userDataLength ) void *userData,
592  IN_LENGTH_SHORT const int userDataMaxLength,
593  OUT_LENGTH_SHORT_Z int *userDataLength,
594  const USER_INFO *userInfoPtr )
595  {
596  const USER_FILE_INFO *userFileInfo = &userInfoPtr->userFileInfo;
597  STREAM stream;
598  int status;
599 
600  assert( isWritePtr( userData, userDataMaxLength ) );
601  assert( isWritePtr( userDataLength, sizeof( int ) ) );
602  assert( isReadPtr( userInfoPtr, sizeof( USER_INFO ) ) );
603 
604  REQUIRES( userDataMaxLength > 0 && \
605  userDataMaxLength < MAX_INTLENGTH_SHORT );
606 
607  /* Clear return values */
608  memset( userData, 0, min( 16, userDataMaxLength ) );
609  *userDataLength = 0;
610 
611  /* Write the user information to a memory buffer */
612  sMemOpen( &stream, userData, userDataMaxLength );
613  writeSequence( &stream, sizeofShortInteger( userFileInfo->type ) + \
614  2 * sizeofObject( KEYID_SIZE ) + \
615  sizeofObject( userFileInfo->userNameLength ) );
616  writeEnumerated( &stream, userFileInfo->type, DEFAULT_TAG );
617  writeOctetString( &stream, userFileInfo->userID, KEYID_SIZE,
618  DEFAULT_TAG );
619  writeOctetString( &stream, userFileInfo->creatorID, KEYID_SIZE,
620  DEFAULT_TAG );
621  status = writeCharacterString( &stream, userFileInfo->userName,
622  userFileInfo->userNameLength,
623  BER_STRING_UTF8 );
624  if( cryptStatusOK( status ) )
625  *userDataLength = stell( &stream );
626  sMemDisconnect( &stream );
627 
628  return( status );
629  }
630 
631 /* Send user data to a user keyset */
632 
634 static int commitUserData( IN_HANDLE const CRYPT_KEYSET iUserKeyset,
635  const USER_INFO *userInfoPtr,
636  IN_BUFFER( userDataLength ) const void *userData,
637  IN_LENGTH_SHORT const int userDataLength )
638  {
640  int status;
641 
642  assert( isReadPtr( userInfoPtr, sizeof( USER_INFO ) ) );
643  assert( isReadPtr( userData, userDataLength ) );
644 
645  REQUIRES( isHandleRangeValid( iUserKeyset ) );
646  REQUIRES( userDataLength > 0 && userDataLength < MAX_INTLENGTH_SHORT );
647 
648  /* Add the user ID and SO-signed user info to the keyset */
649  setMessageData( &msgData, ( MESSAGE_CAST ) userData, userDataLength );
650  status = krnlSendMessage( iUserKeyset, IMESSAGE_SETATTRIBUTE_S,
651  &msgData, CRYPT_IATTRIBUTE_USERINFO );
652  if( cryptStatusOK( status ) )
653  {
654  setMessageData( &msgData,
655  ( MESSAGE_CAST ) userInfoPtr->userFileInfo.userID,
656  KEYID_SIZE );
657  status = krnlSendMessage( iUserKeyset, IMESSAGE_SETATTRIBUTE_S,
658  &msgData, CRYPT_IATTRIBUTE_USERID );
659  }
660  return( status );
661  }
662 
663 /* Read a user's info from a user keyset and verify it using the creating
664  SO's key */
665 
666 #if 0
669 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
670 static int getCheckUserInfo( INOUT USER_FILE_INFO *userFileInfoPtr,
671  IN_INT_SHORT_Z const int fileRef )
672  {
675  CRYPT_KEYSET iUserKeyset;
676  MESSAGE_CREATEOBJECT_INFO createInfo;
677  MESSAGE_KEYMGMT_INFO getkeyInfo;
678  STREAM stream;
679  DYNBUF userDataDB;
680  void *hashDataPtr, *signaturePtr;
681  int soFileRef, hashDataLength, signatureLength, status;
682 
683  assert( isWritePtr( userFileInfoPtr, sizeof( USER_FILE_INFO ) ) );
684 
685  REQUIRES( fileRef >= 0 && fileRef < MAX_INTLENGTH_SHORT );
686 
687  /* Clear return values */
688  memset( userFileInfoPtr, 0, sizeof( USER_FILE_INFO ) );
689 
690  /* Open the user keyset and read the user data from it */
691  status = openUserKeyset( &iUserKeyset, fileRef, CRYPT_KEYOPT_READONLY );
692  if( cryptStatusError( status ) )
693  return( status );
694  status = dynCreate( &userDataDB, iUserKeyset,
695  CRYPT_IATTRIBUTE_USERINFO );
696  krnlSendNotifier( iUserKeyset, IMESSAGE_DECREFCOUNT );
697  if( cryptStatusError( status ) )
698  return( status );
699 
700  /* Burrow into the user info to get the information we need. We do it
701  this way rather than using envelopes because we don't need the full
702  generality of the enveloping process (we know exactly what data to
703  expect) and to avoid the overhead of de-enveloping data every time a
704  user logs in */
705  sMemConnect( &stream, dynData( userDataDB ), dynLength( userDataDB ) );
706  readSequence( &stream, NULL ); /* Outer wrapper */
707  readUniversal( &stream ); /* ContentType OID */
708  readConstructed( &stream, NULL, 0 ); /* Content */
709  readSequence( &stream, NULL );
710  readUniversal( &stream ); /* Version */
711  readSet( &stream, NULL ); /* DigestAlgorithms */
712  readAlgoID( &stream, &hashAlgo );
713  readSequence( &stream, NULL ); /* EncapContentInfo */
714  readUniversal( &stream ); /* ContentType OID */
715  readConstructed( &stream, NULL, 0 ); /* Content type wrapper */
716  status = readGenericHole( &stream, &hashDataLength, 16, DEFAULT_TAG );
717  if( cryptStatusError( status ) )
718  {
719  sMemDisconnect( &stream );
720  dynDestroy( &userDataDB );
721  return( status );
722  }
723  hashDataPtr = sMemBufPtr( &stream );
724 
725  /* Read the user info */
726  status = readUserData( userFileInfoPtr, hashDataPtr, hashDataLength );
727  if( cryptStatusError( status ) )
728  {
729  sMemDisconnect( &stream );
730  dynDestroy( &userDataDB );
731  return( status );
732  }
733 
734  /* Hash the signed data and verify the signature using the SO key */
737  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
739  if( cryptStatusError( status ) )
740  {
741  dynDestroy( &userDataDB );
742  sMemDisconnect( &stream );
743  return( status );
744  }
745  iHashContext = createInfo.cryptHandle;
746  krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, hashDataPtr,
747  hashDataLength );
748  status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, "", 0 );
749  dynDestroy( &userDataDB );
750  if( cryptStatusError( status ) )
751  {
752  sMemDisconnect( &stream );
753  return( status );
754  }
755 
756  /* Read the signature */
757  status = readSet( &stream, &signatureLength );
758  signaturePtr = sMemBufPtr( &stream );
759  sMemDisconnect( &stream );
760  if( cryptStatusError( status ) )
761  {
762  krnlSendNotifier( iHashContext, IMESSAGE_DECREFCOUNT );
763  return( status );
764  }
765 
766  /* Open the SO keyset and read the SO public key from it */
767  status = soFileRef = \
768  findUserIndexEntry( USERID_USERID, userFileInfoPtr->creatorID,
769  KEYID_SIZE );
770  if( cryptStatusOK( status ) )
771  status = openUserKeyset( &iUserKeyset, soFileRef,
773  if( cryptStatusError( status ) )
774  {
775  krnlSendNotifier( iHashContext, IMESSAGE_DECREFCOUNT );
776  return( status );
777  }
778  setMessageKeymgmtInfo( &getkeyInfo, CRYPT_IKEYID_KEYID,
779  userFileInfoPtr->creatorID, KEYID_SIZE, NULL, 0,
781  status = krnlSendMessage( iUserKeyset, IMESSAGE_KEY_GETKEY,
782  &getkeyInfo, KEYMGMT_ITEM_PUBLICKEY );
783  krnlSendNotifier( iUserKeyset, IMESSAGE_DECREFCOUNT );
784  if( cryptStatusError( status ) )
785  {
786  krnlSendNotifier( iHashContext, IMESSAGE_DECREFCOUNT );
787  return( status );
788  }
789 
790  /* Verify the signature using the SO key */
791  status = iCryptCheckSignatureEx( signaturePtr, signatureLength,
793  getkeyInfo.cryptHandle, iHashContext,
794  NULL );
795  krnlSendNotifier( iHashContext, IMESSAGE_DECREFCOUNT );
797  if( cryptStatusError( status ) )
798  return( status );
799 
801  /* MAC (???) using password - needs PKCS #15 changes */
804  return( status );
805  }
806 #endif
808 /****************************************************************************
809 * *
810 * SO Management Functions *
811 * *
812 ****************************************************************************/
813 
814 /* Return the primary SO user info. This is used as a template to create
815  the primary SO user after a zeroise */
816 
818  {
819  return( &primarySOInfo );
820  }
821 
822 /* Sign the user info and write it to the user keyset */
823 
825 static int signUserData( IN_HANDLE const CRYPT_KEYSET iUserKeyset,
826  const USER_INFO *userInfoPtr,
828  {
829  BYTE userInfoBuffer[ USERDATA_BUFFERSIZE + 8 ];
830  int userInfoLength, status;
831 
832  assert( isReadPtr( userInfoPtr, sizeof( USER_INFO ) ) );
833 
834  REQUIRES( isHandleRangeValid( iUserKeyset ) );
835  REQUIRES( isHandleRangeValid( iSignContext ) );
836 
837  /* Set dummy user data */
838  memset( userInfoBuffer, '*', 16 );
839  userInfoLength = 16;
840 
841  /* Sign the data via an envelope. This is kind of heavyweight, but it's
842  OK because we rarely create new users and it saves having to hand-
843  assemble the data like the PKCS #15 code does */
844  status = envelopeSign( userInfoBuffer, userInfoLength,
845  userInfoBuffer, USERDATA_BUFFERSIZE,
846  &userInfoLength, CRYPT_CONTENT_DATA,
847  iSignContext, CRYPT_UNUSED );
848  if( cryptStatusError( status ) )
849  return( status );
850 
851  return( CRYPT_ERROR_SIGNATURE );
852  }
853 
854 CHECK_RETVAL \
855 static int sigCheckUserData( void )
856  {
857  return( CRYPT_ERROR_SIGNATURE );
858  }
859 
860 /* Create an SO private key and write it to the user keyset */
861 
862 CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 3 ) ) \
863 static int createSOKey( IN_HANDLE const CRYPT_KEYSET iUserKeyset,
864  INOUT USER_INFO *userInfoPtr,
865  IN_BUFFER( passwordLength ) const char *password,
866  IN_LENGTH_SHORT const int passwordLength )
867  {
868  const USER_FILE_INFO *userFileInfo = &userInfoPtr->userFileInfo;
869  MESSAGE_CREATEOBJECT_INFO createInfo;
871  const int actionPerms = MK_ACTION_PERM( MESSAGE_CTX_SIGN,
873  MK_ACTION_PERM( MESSAGE_CTX_SIGCHECK,
875  int status;
876 
877  assert( isReadPtr( userInfoPtr, sizeof( USER_INFO ) ) );
878  assert( isReadPtr( password, passwordLength ) );
879 
880  REQUIRES( isHandleRangeValid( iUserKeyset ) );
881  REQUIRES( passwordLength > 0 && passwordLength < MAX_INTLENGTH_SHORT );
882 
883  /* Create the SO private key, making it internal and signature-only */
886  &createInfo, OBJECT_TYPE_CONTEXT );
887  if( cryptStatusError( status ) )
888  return( status );
889  setMessageData( &msgData, ( MESSAGE_CAST ) userFileInfo->userName,
890  min( userFileInfo->userNameLength, CRYPT_MAX_TEXTSIZE ) );
892  &msgData, CRYPT_CTXINFO_LABEL );
893  status = krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_CTX_GENKEY );
894  if( cryptStatusOK( status ) )
895  status = krnlSendMessage( createInfo.cryptHandle,
897  ( int * ) &actionPerms,
898  CRYPT_IATTRIBUTE_ACTIONPERMS );
899  if( cryptStatusError( status ) )
900  {
902  return( status );
903  }
904 
905  /* Add the SO private key to the keyset */
906  status = addKey( iUserKeyset, createInfo.cryptHandle,
907  userFileInfo->userID, KEYID_SIZE, password,
908  passwordLength, TRUE );
909  if( cryptStatusError( status ) )
910  {
912  return( status );
913  }
914 
915  userInfoPtr->iCryptContext = createInfo.cryptHandle;
916  return( CRYPT_OK );
917  }
918 
919 #if 0 /* Currently unused, for future use for CA users */
920 
921 /* Create a CA secret key and write it to the user keyset */
922 
923 CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 3 ) ) \
924 static int createCAKey( IN_HANDLE const CRYPT_KEYSET iUserKeyset,
925  INOUT USER_INFO *userInfoPtr,
926  IN_BUFFER( passwordLength ) const char *password,
927  IN_LENGTH_SHORT const int passwordLength )
928  {
929  MESSAGE_CREATEOBJECT_INFO createInfo;
931  const int actionPerms = MK_ACTION_PERM( MESSAGE_CTX_ENCRYPT,
933  MK_ACTION_PERM( MESSAGE_CTX_DECRYPT,
935  int status;
936 
937  assert( isReadPtr( userInfoPtr, sizeof( USER_INFO ) ) );
938  assert( isReadPtr( password, passwordLength ) );
939 
940  REQUIRES( isHandleRangeValid( iUserKeyset ) );
941  REQUIRES( passwordLength > 0 && passwordLength < MAX_INTLENGTH_SHORT );
942 
943  /* Create the CA secret key, making it internal-only */
946  &createInfo, OBJECT_TYPE_CONTEXT );
947  if( cryptStatusError( status ) )
948  return( status );
949  setMessageData( &msgData, userInfoPtr->userID, KEYID_SIZE );
951  &msgData, CRYPT_CTXINFO_LABEL );
952  status = krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_CTX_GENKEY );
953  if( cryptStatusOK( status ) )
954  status = krnlSendMessage( createInfo.cryptHandle,
956  ( int * ) &actionPerms,
957  CRYPT_IATTRIBUTE_ACTIONPERMS );
958  if( cryptStatusError( status ) )
959  {
961  return( status );
962  }
963 
964  /* Add the CA secret key to the keyset */
965  status = addKey( iUserKeyset, createInfo.cryptHandle,
966  userInfoPtr->userID, KEYID_SIZE, password,
967  passwordLength, FALSE );
968  if( cryptStatusError( status ) )
969  {
971  return( status );
972  }
973 
974  return( CRYPT_OK );
975  }
976 #endif /* 0 */
977 
978 /* Create a primary SO user. This can only occur when we're in the zeroised
979  state */
980 
981 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
982 static int createPrimarySoUser( INOUT USER_INFO *userInfoPtr,
983  IN_BUFFER( passwordLength ) const char *password,
984  IN_LENGTH_SHORT const int passwordLength )
985  {
986  CRYPT_KEYSET iIndexKeyset, iUserKeyset;
987  USER_FILE_INFO userIndex;
988  BYTE userData[ USERDATA_BUFFERSIZE + 8 ];
989  int userDataLength = DUMMY_INIT, status;
990 
991  assert( isWritePtr( userInfoPtr, sizeof( USER_INFO ) ) );
992  assert( isReadPtr( password, passwordLength ) );
993 
994  REQUIRES( passwordLength > 0 && passwordLength < MAX_INTLENGTH_SHORT );
995 
996  /* Create the user index file and user file for the primary SO user */
997  status = openIndexKeyset( &iIndexKeyset, CRYPT_KEYOPT_CREATE );
998  if( cryptStatusError( status ) )
999  return( status );
1000  status = openUserKeyset( &iUserKeyset, 0, CRYPT_KEYOPT_CREATE );
1001  if( cryptStatusError( status ) )
1002  {
1003  krnlSendNotifier( iIndexKeyset, IMESSAGE_DECREFCOUNT );
1004  return( status );
1005  }
1006 
1007  /* Update the index file */
1008  memcpy( &userIndex, &userInfoPtr->userFileInfo,
1009  sizeof( USER_FILE_INFO ) );
1010  userIndex.fileRef = 0;
1011  status = writeUserIndex( iIndexKeyset, &userIndex, MAX_USER_OBJECTS );
1012  krnlSendNotifier( iIndexKeyset, IMESSAGE_DECREFCOUNT );
1013  if( cryptStatusError( status ) )
1014  {
1015  /* We couldn't update the index file, delete the newly-created user
1016  keyset. Since we haven't written anything to it, it's zero-length
1017  so it's deleted automatically on close */
1018  krnlSendNotifier( iUserKeyset, IMESSAGE_DECREFCOUNT );
1019  return( status );
1020  }
1021  userInfoPtr->iKeyset = iUserKeyset;
1022 
1023  /* Create the SO key and the user keyset file */
1024  status = createSOKey( iUserKeyset, userInfoPtr, password,
1025  passwordLength );
1026  if( cryptStatusOK( status ) )
1027  status = writeUserData( userData, USERDATA_BUFFERSIZE,
1028  &userDataLength, userInfoPtr );
1029  if( cryptStatusOK( status ) )
1030  status = commitUserData( iUserKeyset, userInfoPtr, userData,
1031  userDataLength );
1032  if( cryptStatusError( status ) )
1033  {
1034  /* The primary SO create failed, return to the zeroised state.
1035  Since we're already in an exception state here there's not
1036  much that we can do if the zeroise fails */
1037  krnlSendNotifier( iUserKeyset, IMESSAGE_DECREFCOUNT );
1038  ( void ) zeroiseUsers( userInfoPtr );
1039  return( status );
1040  }
1041 
1043 /*status = createCAKey( iUserKeyset, userInfoPtr, password, passwordLength );*/
1046  return( status );
1047  }
1048 
1049 /****************************************************************************
1050 * *
1051 * User Management Functions *
1052 * *
1053 ****************************************************************************/
1054 
1055 /* Check whether a supplied password is the zeroise password */
1056 
1058 BOOLEAN isZeroisePassword( IN_BUFFER( passwordLen ) const char *password,
1059  IN_LENGTH_SHORT const int passwordLen )
1060  {
1061  assert( isReadPtr( password, passwordLen ) );
1062 
1063  REQUIRES( passwordLen > 0 && passwordLen < MAX_INTLENGTH_SHORT );
1064 
1065  if( passwordLen != PRIMARYSO_PASSWORD_LENGTH )
1066  return( FALSE );
1067  return( !memcmp( password, PRIMARYSO_PASSWORD,
1069  !memcmp( password, PRIMARYSO_ALTPASSWORD,
1071  TRUE : FALSE );
1072  }
1073 
1074 /* Perform a zeroise */
1075 
1076 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
1077 int zeroiseUsers( INOUT USER_INFO *userInfoPtr )
1078  {
1079  USER_INDEX_INFO *userIndexInfo = userInfoPtr->userIndexPtr;
1080  USER_FILE_INFO *userIndex = userIndexInfo->userIndex;
1081  char userFilePath[ MAX_PATH_LENGTH + 1 + 8 ];
1082  int userFilePathLen, i, iterationCount, status;
1083 
1084  assert( isWritePtr( userInfoPtr, sizeof( USER_INFO ) ) );
1085 
1086  /* Read the user index and step through each entry clearing the user
1087  info for it */
1088  for( i = 0, iterationCount = 0;
1089  i < userIndexInfo->lastEntry && \
1090  iterationCount < FAILSAFE_ITERATIONS_LARGE;
1091  i++, iterationCount++ )
1092  {
1093  char userFileName[ 16 + 8 ];
1094 
1095  /* Erase the given user keyset */
1096  sprintf_s( userFileName, 16, "u%06x", userIndex[ i ].fileRef );
1097  status = fileBuildCryptlibPath( userFilePath, MAX_PATH_LENGTH,
1098  &userFilePathLen, userFileName,
1099  strlen( userFileName ),
1101  if( cryptStatusOK( status ) )
1102  {
1103  userFilePath[ userFilePathLen ] = '\0';
1104  fileErase( userFilePath );
1105  }
1106  }
1107  ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
1108 
1109  /* Erase the index file */
1110  status = fileBuildCryptlibPath( userFilePath, MAX_PATH_LENGTH,
1111  &userFilePathLen, "index", 5,
1113  if( cryptStatusOK( status ) )
1114  {
1115  userFilePath[ userFilePathLen ] = '\0';
1116  fileErase( userFilePath );
1117  }
1118  return( status );
1119  }
1120 
1121 /* Create a user keyset */
1122 
1123 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1124 static int createUserKeyset( INOUT USER_INFO *defaultUserInfoPtr,
1125  INOUT USER_INFO *newUserInfoPtr )
1126  {
1127  CRYPT_KEYSET iIndexKeyset, iUserKeyset;
1128  USER_FILE_INFO *userFileInfo = &newUserInfoPtr->userFileInfo;
1129  USER_FILE_INFO *userIndexPtr;
1130  int status;
1131 
1132  assert( isReadPtr( defaultUserInfoPtr, sizeof( USER_INFO ) ) );
1133  assert( isReadPtr( newUserInfoPtr, sizeof( USER_INFO ) ) );
1134 
1135  /* Try and open the index file */
1136  status = openIndexKeyset( &iIndexKeyset, CRYPT_IKEYOPT_EXCLUSIVEACCESS );
1137  if( cryptStatusError( status ) )
1138  return( status );
1139 
1140  /* Create the index entry for the new user */
1141  status = createUserEntry( &userIndexPtr,
1142  defaultUserInfoPtr->userIndexPtr,
1143  MAX_USER_OBJECTS, userFileInfo );
1144  if( cryptStatusError( status ) )
1145  {
1146  krnlSendNotifier( iIndexKeyset, IMESSAGE_DECREFCOUNT );
1147  return( status );
1148  }
1149 
1150  /* Create the user keyset */
1151  status = openUserKeyset( &iUserKeyset, userFileInfo->fileRef,
1153  if( cryptStatusError( status ) )
1154  {
1155  krnlSendNotifier( iIndexKeyset, IMESSAGE_DECREFCOUNT );
1156  return( status );
1157  }
1158 
1159  /* We've got the user keyset and info created, update the in-memory
1160  index and index file */
1161  memcpy( userIndexPtr, userFileInfo, sizeof( USER_FILE_INFO ) );
1162  status = writeUserIndex( iIndexKeyset, defaultUserInfoPtr->userIndexPtr,
1163  MAX_USER_OBJECTS );
1164  krnlSendNotifier( iIndexKeyset, IMESSAGE_DECREFCOUNT );
1165  if( cryptStatusError( status ) )
1166  {
1167  /* We couldn't update the index file, delete the newly-created user
1168  keyset (since we haven't written anything to it, it's zero-length
1169  so it's deleted automatically on close) */
1170  krnlSendNotifier( iUserKeyset, IMESSAGE_DECREFCOUNT );
1171  }
1172  krnlSendNotifier( iIndexKeyset, IMESSAGE_DECREFCOUNT );
1173 
1174  /* Clean up */
1175  return( status );
1176  }
1177 
1178 /* Set/change the password for a user object */
1179 
1180 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1181 int setUserPassword( INOUT USER_INFO *userInfoPtr,
1182  IN_BUFFER( passwordLength ) const char *password,
1183  IN_LENGTH_SHORT const int passwordLength )
1184  {
1185  CRYPT_KEYSET iUserKeyset;
1186  USER_FILE_INFO *userFileInfo = &userInfoPtr->userFileInfo;
1187  int status;
1188 
1189  assert( isReadPtr( userInfoPtr, sizeof( USER_INFO ) ) );
1190  assert( isReadPtr( password, passwordLength ) );
1191 
1192  REQUIRES( passwordLength > 0 && passwordLength < MAX_INTLENGTH_SHORT );
1193 
1197 {
1198 USER_FILE_INFO dummyUserInfo = { 0 }, *userFileInfoPtr = &dummyUserInfo;
1199 USER_INFO userInfo;
1200 
1201 ( void ) readUserData( userFileInfoPtr, "", 0 );
1202 ( void ) signUserData( 0, &userInfo, 0 );
1203 ( void ) sigCheckUserData();
1204 ( void ) createSOKey( 0, &userInfo, "", 0 );
1205 ( void ) createUserKeyset( &userInfo, &userInfo );
1206 }
1209  /* No-one can ever directly set the default SO password */
1210  if( passwordLength == PRIMARYSO_PASSWORD_LENGTH && \
1211  ( !memcmp( password, PRIMARYSO_PASSWORD,
1213  !memcmp( password, PRIMARYSO_ALTPASSWORD,
1215  return( CRYPT_ERROR_WRONGKEY );
1216 
1217  /* If we're setting the password for the primary SO in the zeroised
1218  state, create a new user keyset and SO authentication key and write
1219  the details to the keyset */
1220  if( userFileInfo->fileRef == -1 )
1221  {
1222  status = createPrimarySoUser( userInfoPtr, password,
1223  passwordLength );
1224 
1225  return( status );
1226  }
1227 
1228  /* Open an existing user keyset */
1229  status = openUserKeyset( &iUserKeyset, userFileInfo->fileRef,
1231  if( cryptStatusError( status ) )
1232  return( status );
1233 
1235  /* set state = USER_INITED */
1236  /* write MAC( ??? ) to user file - needs PKCS #15 changes */
1239  /* Close the keyset and commit the changes */
1240  krnlSendNotifier( iUserKeyset, IMESSAGE_DECREFCOUNT );
1241 
1242  /* The password has been set, we're now in the user inited state */
1243  userFileInfo->state = USER_STATE_USERINITED;
1244  return( CRYPT_OK );
1245  }
1246 
1247 /* Initialise the user index in the default user object from the index file,
1248  and clean up after we're done with it */
1249 
1250 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
1251 int initUserIndex( OUT_OPT_PTR void **userIndexPtrPtr )
1252  {
1253  CRYPT_KEYSET iIndexKeyset;
1254  USER_INDEX_INFO *userIndexInfo;
1255  int noEntries, status;
1256 
1257  assert( isWritePtr( userIndexPtrPtr, sizeof( void * ) ) );
1258 
1259  /* Clear return value */
1260  *userIndexPtrPtr = NULL;
1261 
1262  /* Open the index file and read the index entries from it. We open it
1263  in exclusive mode since nothing else should be accessing it at this
1264  point.
1265 
1266  What to do if this fails is a bit tricky (see the comment in
1267  createDefaultUserObject() for the config file read), however for the
1268  index keyset it's a bit more clear-cut, we shouldn't fail if the
1269  access fails so we just skip it and continue, making it look as if
1270  we're in the zeroised state */
1271  status = openIndexKeyset( &iIndexKeyset, CRYPT_IKEYOPT_EXCLUSIVEACCESS );
1272  if( cryptStatusError( status ) )
1273  {
1274  /* If there's no index file present, we're already in the zeroised
1275  state */
1276  if( status == CRYPT_ERROR_NOTFOUND )
1277  return( CRYPT_OK );
1278 
1279  /* If keysets are disabled, we fall back to the hardwired
1280  configuration parameters */
1281  if( status == CRYPT_ERROR_NOTAVAIL )
1282  return( CRYPT_OK );
1283 
1284  /* Warn the user (in debug mode) that something went wrong */
1285  DEBUG_DIAG(( "Couldn't read user index, assuming zeroised state" ));
1286  assert( DEBUG_WARN );
1287  DEBUG_PRINT(( "User index read failed with status %d.\n", status ));
1288 
1289 #if 0 /* Another problematic choice, should we potentially destroy a
1290  damaged index or leave it for the user to fix up? Since this
1291  situation would never normally occur we leave it as a user-to-fix
1292  for now */
1293  /* If there's something there but it's damaged, delete it so that we
1294  can start again */
1295  if( status == CRYPT_ERROR_BADDATA )
1296  {
1297  char userFilePath[ MAX_PATH_LENGTH + 1 + 8 ];
1298  int userFilePathLen;
1299 
1300  status = fileBuildCryptlibPath( userFilePath, MAX_PATH_LENGTH,
1301  &userFilePathLen, "index", 5,
1303  if( cryptStatusOK( status ) )
1304  {
1305  userFilePath[ userFilePathLen ] = '\0';
1306  fileErase( userFilePath );
1307  }
1308  }
1309 #endif /* 0 */
1310 
1311  return( CRYPT_OK );
1312  }
1313 
1314  /* Allocate room for the user index and read it into the default user
1315  object */
1316  if( ( userIndexInfo = clAlloc( "initUserIndex", \
1317  sizeof( USER_INDEX_INFO ) ) ) == NULL )
1318  return( CRYPT_ERROR_MEMORY );
1319  memset( userIndexInfo, 0, sizeof( USER_INDEX_INFO ) );
1320  status = noEntries = readIndex( iIndexKeyset, userIndexInfo->userIndex,
1321  MAX_USER_OBJECTS );
1322  krnlSendNotifier( iIndexKeyset, IMESSAGE_DECREFCOUNT );
1323  if( cryptStatusError( status ) )
1324  {
1325  clFree( "initUserIndex", userIndexInfo );
1326  return( status );
1327  }
1328  userIndexInfo->lastEntry = noEntries;
1329  *userIndexPtrPtr = userIndexInfo;
1330 
1331  return( CRYPT_OK );
1332  }
1333 
1334 STDC_NONNULL_ARG( ( 1 ) ) \
1335 void endUserIndex( INOUT void *userIndexPtr )
1336  {
1337  USER_INDEX_INFO *userIndexInfo = userIndexPtr;
1338 
1339  assert( isWritePtr( userIndexInfo, sizeof( USER_INDEX_INFO ) ) );
1340 
1341  zeroise( userIndexInfo, sizeof( USER_INDEX_INFO ) );
1342  clFree( "endUserIndex", userIndexInfo );
1343  }