cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
user_attr.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib User Attribute 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 "trustmgr.h"
12  #include "user.h"
13 #else
14  #include "cert/trustmgr.h"
15  #include "misc/user.h"
16 #endif /* Compiler-specific includes */
17 
18 /****************************************************************************
19 * *
20 * Utility Functions *
21 * *
22 ****************************************************************************/
23 
24 /* Exit after setting extended error information */
25 
27 static int exitError( INOUT USER_INFO *userInfoPtr,
28  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus,
29  IN_ENUM( CRYPT_ERRTYPE ) const CRYPT_ERRTYPE_TYPE errorType,
30  IN_ERROR const int status )
31  {
32  assert( isWritePtr( userInfoPtr, sizeof( USER_INFO ) ) );
33 
34  REQUIRES( isAttribute( errorLocus ) || \
35  isInternalAttribute( errorLocus ) );
36  REQUIRES( errorType > CRYPT_ERRTYPE_NONE && \
37  errorType < CRYPT_ERRTYPE_LAST );
38  REQUIRES( cryptStatusError( status ) );
39 
40  setErrorInfo( userInfoPtr, errorLocus, errorType );
41  return( status );
42  }
43 
45 static int exitErrorInited( INOUT USER_INFO *userInfoPtr,
46  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus )
47  {
48  assert( isWritePtr( userInfoPtr, sizeof( USER_INFO ) ) );
49 
50  REQUIRES( isAttribute( errorLocus ) || \
51  isInternalAttribute( errorLocus ) );
52 
53  return( exitError( userInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_PRESENT,
55  }
56 
58 static int exitErrorNotFound( INOUT USER_INFO *userInfoPtr,
59  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus )
60  {
61  assert( isWritePtr( userInfoPtr, sizeof( USER_INFO ) ) );
62 
63  REQUIRES( isAttribute( errorLocus ) || \
64  isInternalAttribute( errorLocus ) );
65 
66  return( exitError( userInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_ABSENT,
68  }
69 
70 /* Process a set-attribute operation that initiates an operation that's
71  performed in two phases. The reason for the split is that the second
72  phase doesn't require the use of the user object data any more and can be
73  a somewhat lengthy process due to disk accesses or lengthy crypto
74  operations. Because of this we unlock the user object between the two
75  phases to ensure that the second phase doesn't stall all other operations
76  that require this user object */
77 
79 static int twoPhaseConfigUpdate( INOUT USER_INFO *userInfoPtr,
80  IN_INT_Z const int value )
81  {
83  CONFIG_DISPOSITION_TYPE disposition;
84  char userFileName[ 16 + 8 ];
85  void *data = NULL;
86  int length = 0, commitStatus, refCount, status;
87 
88  assert( isWritePtr( userInfoPtr, sizeof( USER_INFO ) ) );
89 
90  REQUIRES( value == FALSE );
91 
92  /* Set up the filename that we want to access */
93  if( userInfoPtr->userFileInfo.fileRef == CRYPT_UNUSED )
94  strlcpy_s( userFileName, 16, "cryptlib" );
95  else
96  {
97  sprintf_s( userFileName, 16, "u%06x",
98  userInfoPtr->userFileInfo.fileRef );
99  }
100 
101  /* Determine what we have to do with the configuation information */
102  status = getConfigDisposition( userInfoPtr->configOptions,
103  userInfoPtr->configOptionsCount,
104  userInfoPtr->trustInfoPtr,
105  &disposition );
106  if( cryptStatusError( status ) )
107  return( status );
108  switch( disposition )
109  {
111  /* There's nothing to do, we're done */
112  return( CRYPT_OK );
113 
115  /* There's nothing to write, delete the configuration file */
116  return( deleteConfig( userFileName ) );
117 
119  /* There are only trusted certificates present, if they're
120  unchanged from earlier then there's nothing to do */
121  if( !userInfoPtr->trustInfoChanged )
122  return( CRYPT_OK );
123 
124  /* Remember where the trusted certificates are coming from */
125  iTrustedCertUserObject = userInfoPtr->objectHandle;
126  break;
127 
130  /* There's configuration data to write, prepare it */
131  status = prepareConfigData( userInfoPtr->configOptions,
132  userInfoPtr->configOptionsCount,
133  &data, &length );
134  if( cryptStatusError( status ) )
135  return( status );
136  if( disposition == CONFIG_DISPOSITION_BOTH )
137  {
138  /* There are certificates present as well, remember where
139  they're coming from */
140  iTrustedCertUserObject = userInfoPtr->objectHandle;
141  }
142  break;
143 
144  default:
145  retIntError();
146  }
147 
148  /* We've got the configuration data (if there is any) in a memory
149  buffer, we can unlock the user object to allow external access while
150  we commit the in-memory data to disk. This also sends any trusted
151  certificates in the user object to the configuration file alongside
152  the data */
153  status = krnlSuspendObject( userInfoPtr->objectHandle, &refCount );
154  ENSURES( cryptStatusOK( status ) );
155  commitStatus = commitConfigData( userFileName, data, length,
156  iTrustedCertUserObject );
157  if( disposition == CONFIG_DISPOSITION_DATA_ONLY || \
158  disposition == CONFIG_DISPOSITION_BOTH )
159  clFree( "userMessageFunction", data );
160  status = krnlResumeObject( userInfoPtr->objectHandle, refCount );
161  if( cryptStatusError( status ) )
162  {
163  /* Handling errors at this point is rather tricky because an error
164  response from krnlResumeObject() is a can't-occur condition. In
165  particular this will mean that we return to the kernel with the
166  user object released, which will cause it to throw an exception
167  due to the inconsistent object state. On the other hand we can
168  only get to this point because of an exception condition anyway
169  so it's just going to propagate the exception back */
170  retIntError();
171  }
172  if( cryptStatusOK( commitStatus ) )
173  userInfoPtr->trustInfoChanged = FALSE;
174 
175  return( commitStatus );
176  }
177 
179 static int twoPhaseSelftest( INOUT USER_INFO *userInfoPtr,
180  IN_INT_Z const int value )
181  {
182  const CRYPT_USER iCryptUser = userInfoPtr->objectHandle;
183  int refCount, selfTestStatus, status;
184 
185  assert( isWritePtr( userInfoPtr, sizeof( USER_INFO ) ) );
186 
187  REQUIRES( value == TRUE );
188 
189  /* It's a self-test, forward the message to the system object with
190  the user object unlocked, tell the system object to perform its self-
191  test, and then re-lock the user object and set the self-test result
192  value. Since the self-test configuration setting will be marked as
193  in-use at this point (to avoid having another thread update it while
194  the user object was unlocked) it can't be written to directly so we
195  have to update it via setOptionSpecial(). In addition since this is
196  now an action message we forward it as a MESSAGE_SELFTEST since the
197  CRYPT_OPTION_SELFTESTOK attribute only applies to the user object.
198 
199  An alternative way to handle this would be implement an advisory-
200  locking mechanism for configuration options, but this adds a great
201  deal of complexity just to handle this one single case so until
202  there's a wider need for general-purpose configuration option locking
203  the current approach will do */
204  status = krnlSuspendObject( iCryptUser, &refCount );
205  ENSURES( cryptStatusOK( status ) );
206  selfTestStatus = krnlSendNotifier( SYSTEM_OBJECT_HANDLE,
208  status = krnlResumeObject( iCryptUser, refCount );
209  /* See comment above on krnlResumeObject() error handling */
210  if( cryptStatusError( status ) )
211  return( status );
212  return( setOptionSpecial( userInfoPtr->configOptions,
213  userInfoPtr->configOptionsCount,
215  cryptStatusOK( selfTestStatus ) ? \
216  TRUE : FALSE ) );
217  }
218 
219 /****************************************************************************
220 * *
221 * Get Attributes *
222 * *
223 ****************************************************************************/
224 
225 /* Get a numeric/boolean attribute */
226 
228 int getUserAttribute( INOUT USER_INFO *userInfoPtr,
229  OUT_INT_Z int *valuePtr,
231  {
232  int status;
233 
234  assert( isWritePtr( userInfoPtr, sizeof( USER_INFO ) ) );
235  assert( isWritePtr( valuePtr, sizeof( int ) ) );
236 
237  REQUIRES( isAttribute( attribute ) || \
238  isInternalAttribute( attribute ) );
239 
240  /* Clear return value */
241  *valuePtr = 0;
242 
243  switch( attribute )
244  {
248  {
249  CRYPT_CERTIFICATE caCert;
250 
251  /* Make sure that the key type that we're after is present in
252  the object */
253  if( userInfoPtr->iCryptContext == CRYPT_UNUSED )
254  return( exitErrorNotFound( userInfoPtr, attribute ) );
255 
256  /* Since the CA signing key tied to the user object is meant to
257  be used only through cryptlib-internal means we shouldn't
258  really be returning it to the caller. We can return the
259  ssociated CA cert, but this may be an internal-only object
260  that the caller can't do anything with. To avoid this
261  problem we isolate the cert by returning a copy of the
262  associated certificate object */
263  status = krnlSendMessage( userInfoPtr->iCryptContext,
264  IMESSAGE_GETATTRIBUTE, &caCert,
265  CRYPT_IATTRIBUTE_CERTCOPY );
266  if( cryptStatusOK( status ) )
267  *valuePtr = caCert;
268  return( status );
269  }
270 
271 #ifdef USE_CERTIFICATES
272  case CRYPT_IATTRIBUTE_CTL:
273  {
274  MESSAGE_CREATEOBJECT_INFO createInfo;
275 
276  /* Check whether there are actually trusted certs present */
277  if( !trustedCertsPresent( userInfoPtr->trustInfoPtr ) )
278  return( CRYPT_ERROR_NOTFOUND );
279 
280  /* Create a cert chain meta-object to hold the overall set of
281  certs */
282  setMessageCreateObjectInfo( &createInfo,
286  &createInfo, OBJECT_TYPE_CERTIFICATE );
287  if( cryptStatusError( status ) )
288  return( status );
289 
290  /* Assemble the trusted certs into the cert chain */
291  status = enumTrustedCerts( userInfoPtr->trustInfoPtr,
292  createInfo.cryptHandle, CRYPT_UNUSED );
293  if( cryptStatusOK( status ) )
294  *valuePtr = createInfo.cryptHandle;
295  else
297  return( status );
298  }
299 #endif /* USE_CERTIFICATES */
300  }
301 
302  /* Anything else has to be a configuration option */
303  REQUIRES( attribute > CRYPT_OPTION_FIRST && \
304  attribute < CRYPT_OPTION_LAST );
305 
306  /* A numeric-value get can never fail because we always have default
307  values present */
308  return( getOption( userInfoPtr->configOptions,
309  userInfoPtr->configOptionsCount, attribute,
310  valuePtr ) );
311  }
312 
313 /* Get a string attribute */
314 
315 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
316 int getUserAttributeS( INOUT USER_INFO *userInfoPtr,
319  {
320  const void *string;
321  int stringLen, status;
322 
323  assert( isWritePtr( userInfoPtr, sizeof( USER_INFO ) ) );
324  assert( isWritePtr( msgData, sizeof( MESSAGE_DATA ) ) );
325 
326  REQUIRES( isAttribute( attribute ) || \
327  isInternalAttribute( attribute ) );
328 
329  /* This can only be a configuration option */
330  REQUIRES( attribute > CRYPT_OPTION_FIRST && \
331  attribute < CRYPT_OPTION_LAST );
332 
333  /* Check whether there's a configuration value of this type present */
334  status = getOptionString( userInfoPtr->configOptions,
335  userInfoPtr->configOptionsCount, attribute,
336  &string, &stringLen );
337  if( cryptStatusError( status ) )
338  return( status );
339  return( attributeCopy( msgData, string, stringLen ) );
340  }
341 
342 /****************************************************************************
343 * *
344 * Set Attributes *
345 * *
346 ****************************************************************************/
347 
348 /* Set a numeric/boolean attribute */
349 
351 int setUserAttribute( INOUT USER_INFO *userInfoPtr,
352  IN_INT_Z const int value,
353  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute )
354  {
355  int status;
356 
357  assert( isWritePtr( userInfoPtr, sizeof( USER_INFO ) ) );
358 
359  REQUIRES( ( attribute == CRYPT_IATTRUBUTE_CERTKEYSET && \
360  value == CRYPT_UNUSED ) || \
361  ( value >= 0 && value < MAX_INTLENGTH ) );
362  REQUIRES( isAttribute( attribute ) || \
363  isInternalAttribute( attribute ) );
364 
365  switch( attribute )
366  {
370  {
371  const int requiredKeyUsage = \
372  ( attribute == CRYPT_USERINFO_CAKEY_CERTSIGN ) ? \
374  ( attribute == CRYPT_USERINFO_CAKEY_CRLSIGN ) ? \
375  CRYPT_KEYUSAGE_CRLSIGN : KEYUSAGE_SIGN;
376  int attributeValue;
377 
378  /* Make sure that this key type isn't already present in the
379  object */
380  if( userInfoPtr->iCryptContext != CRYPT_UNUSED )
381  return( exitErrorInited( userInfoPtr, attribute ) );
382 
383  /* Make sure that we've been given a signing key */
384  status = krnlSendMessage( value, IMESSAGE_CHECK, NULL,
386  if( cryptStatusError( status ) )
387  return( CRYPT_ARGERROR_NUM1 );
388 
389  /* Make sure that the object has an initialised cert of the
390  correct type associated with it */
391  status = krnlSendMessage( value, IMESSAGE_GETATTRIBUTE,
392  &attributeValue,
394  if( cryptStatusError( status ) || !attributeValue )
395  return( CRYPT_ARGERROR_NUM1 );
396  status = krnlSendMessage( value, IMESSAGE_GETATTRIBUTE,
397  &attributeValue,
399  if( cryptStatusError( status ) ||
400  ( attributeValue != CRYPT_CERTTYPE_CERTIFICATE && \
401  attributeValue != CRYPT_CERTTYPE_CERTCHAIN ) )
402  return( CRYPT_ARGERROR_NUM1 );
403 
404  /* Make sure that the key usage required for this action is
405  permitted. OCSP is a bit difficult since the key may or may
406  not have an OCSP extended usage (depending on whether the CA
407  bothers to set it or not, even if they do they may delegate
408  the functionality to a short-term generic signing key) and the
409  signing ability may be indicated by either a digital signature
410  flag or a nonrepudiation flag depending on whether the CA
411  considers an OCSP signature to be short or long-term, so we
412  just check for a generic signing ability */
413  status = krnlSendMessage( value, IMESSAGE_GETATTRIBUTE,
414  &attributeValue,
416  if( cryptStatusError( status ) || \
417  !( attributeValue & requiredKeyUsage ) )
418  return( CRYPT_ARGERROR_NUM1 );
419 
421  /* Save key in the keyset at some point. Also handle get */
422  /* (gets public key) and delete (removes key), this */
423  /* functionality is only needed for CA users so is left for */
424  /* the full implementation of user roles */
427  return( status );
428  }
429 
430  case CRYPT_IATTRUBUTE_CERTKEYSET:
431  /* If it's a presence check, handle it specially */
432  if( value == CRYPT_UNUSED )
433  {
434  return( trustedCertsPresent( userInfoPtr->trustInfoPtr ) ? \
436  }
437 
438  /* Send all trusted certs to the keyset */
439  return( enumTrustedCerts( userInfoPtr->trustInfoPtr,
440  CRYPT_UNUSED, value ) );
441 
442 #ifdef USE_CERTIFICATES
443  case CRYPT_IATTRIBUTE_CTL:
444  /* Add the certs via the trust list */
445  status = addTrustEntry( userInfoPtr->trustInfoPtr,
446  value, NULL, 0, FALSE );
447  if( cryptStatusOK( status ) )
448  userInfoPtr->trustInfoChanged = TRUE;
449  return( status );
450 #endif /* USE_CERTIFICATES */
451  }
452 
453  /* Anything else has to be a configuration option */
454  REQUIRES( attribute > CRYPT_OPTION_FIRST && \
455  attribute < CRYPT_OPTION_LAST );
456 
457  /* Set the option. If it's not one of the two special options with
458  side-effects, we're done */
459  status = setOption( userInfoPtr->configOptions,
460  userInfoPtr->configOptionsCount, attribute, value );
461  if( attribute != CRYPT_OPTION_CONFIGCHANGED && \
462  attribute != CRYPT_OPTION_SELFTESTOK )
463  return( status );
464 
465  /* If there was a problem setting a side-effects option, don't go any
466  further */
467  if( status != OK_SPECIAL )
468  return( status );
469 
470  /* Complete the processing of the special options */
471  if( attribute == CRYPT_OPTION_CONFIGCHANGED )
472  return( twoPhaseConfigUpdate( userInfoPtr, value ) );
473  return( twoPhaseSelftest( userInfoPtr, value ) );
474  }
475 
476 /* Set a string attribute */
477 
478 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
479 int setUserAttributeS( INOUT USER_INFO *userInfoPtr,
480  IN_BUFFER( dataLength ) const void *data,
481  IN_LENGTH const int dataLength,
482  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute )
483  {
484  assert( isWritePtr( userInfoPtr, sizeof( USER_INFO ) ) );
485  assert( isReadPtr( data, dataLength ) );
486 
487  REQUIRES( dataLength > 0 && dataLength < MAX_INTLENGTH );
488  REQUIRES( isAttribute( attribute ) || \
489  isInternalAttribute( attribute ) );
490 
491  switch( attribute )
492  {
494  return( setUserPassword( userInfoPtr, data, dataLength ) );
495  }
496 
497  /* Anything else has to be a configuration option */
498  REQUIRES( attribute > CRYPT_OPTION_FIRST && \
499  attribute < CRYPT_OPTION_LAST );
500  return( setOptionString( userInfoPtr->configOptions,
501  userInfoPtr->configOptionsCount, attribute,
502  data, dataLength ) );
503  }
504 
505 /****************************************************************************
506 * *
507 * Delete Attributes *
508 * *
509 ****************************************************************************/
510 
511 /* Delete an attribute */
512 
514 int deleteUserAttribute( INOUT USER_INFO *userInfoPtr,
515  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute )
516  {
517  assert( isWritePtr( userInfoPtr, sizeof( USER_INFO ) ) );
518 
519  REQUIRES( isAttribute( attribute ) || \
520  isInternalAttribute( attribute ) );
521 
522  switch( attribute )
523  {
527  return( CRYPT_ERROR_NOTFOUND );
528  }
529 
530  /* Anything else has to be a configuration option */
531  REQUIRES( attribute > CRYPT_OPTION_FIRST && \
532  attribute < CRYPT_OPTION_LAST );
533 
534  return( deleteOption( userInfoPtr->configOptions,
535  userInfoPtr->configOptionsCount, attribute ) );
536  }