cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
dev_attr.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib Crypto Device Attribute Routines *
4 * Copyright Peter Gutmann 1997-2007 *
5 * *
6 ****************************************************************************/
7 
8 #include "crypt.h"
9 #ifdef INC_ALL
10  #include "capabil.h"
11  #include "device.h"
12 #else
13  #include "device/capabil.h"
14  #include "device/device.h"
15 #endif /* Compiler-specific includes */
16 
17 /* When we get random data from a device we run the (practical) FIPS 140
18  tests over the output to make sure that it's really random, at least as
19  far as the tests can tell us. If the data fails the test we get more and
20  try again. The following value defines how many times we retry before
21  giving up. In test runs, a count of 2 failures is reached every ~50,000
22  iterations, 5 is never reached (in fact with 1M tests, 3 is never
23  reached) */
24 
25 #define NO_ENTROPY_FAILURES 5
26 
27 /****************************************************************************
28 * *
29 * Utility Routines *
30 * *
31 ****************************************************************************/
32 
33 /* Exit after setting extended error information */
34 
36 static int exitError( INOUT DEVICE_INFO *deviceInfoPtr,
37  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus,
38  IN_ENUM( CRYPT_ERRTYPE ) const CRYPT_ERRTYPE_TYPE errorType,
39  IN_ERROR const int status )
40  {
41  assert( isWritePtr( deviceInfoPtr, sizeof( DEVICE_INFO ) ) );
42 
43  REQUIRES( isAttribute( errorLocus ) || \
44  isInternalAttribute( errorLocus ) );
45  REQUIRES( errorType > CRYPT_ERRTYPE_NONE && \
46  errorType < CRYPT_ERRTYPE_LAST );
47  REQUIRES( cryptStatusError( status ) );
48 
49  setErrorInfo( deviceInfoPtr, errorLocus, errorType );
50  return( status );
51  }
52 
54 static int exitErrorInited( INOUT DEVICE_INFO *deviceInfoPtr,
55  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus )
56  {
57  assert( isWritePtr( deviceInfoPtr, sizeof( DEVICE_INFO ) ) );
58 
59  REQUIRES( isAttribute( errorLocus ) || \
60  isInternalAttribute( errorLocus ) );
61 
62  return( exitError( deviceInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_PRESENT,
64  }
65 
67 static int exitErrorNotFound( INOUT DEVICE_INFO *deviceInfoPtr,
68  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus )
69  {
70  assert( isWritePtr( deviceInfoPtr, sizeof( DEVICE_INFO ) ) );
71 
72  REQUIRES( isAttribute( errorLocus ) || \
73  isInternalAttribute( errorLocus ) );
74 
75  return( exitError( deviceInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_ABSENT,
77  }
78 
79 /****************************************************************************
80 * *
81 * Read a Random-data Attribute *
82 * *
83 ****************************************************************************/
84 
85 /* Get a random data block with FIPS 140 checking */
86 
88 static int getRandomChecked( INOUT DEVICE_INFO *deviceInfoPtr,
89  OUT_BUFFER_FIXED( length ) void *data,
90  IN_LENGTH_SHORT const int length,
92  {
93  int i;
94 
95  assert( isWritePtr( deviceInfoPtr, sizeof( DEVICE_INFO ) ) );
96  assert( isWritePtr( data, length ) );
97  assert( messageExtInfo == NULL || \
98  ( isWritePtr( messageExtInfo, \
99  sizeof( MESSAGE_FUNCTION_EXTINFO ) ) ) );
100 
101  REQUIRES( length > 0 && length < MAX_INTLENGTH_SHORT );
102 
103  /* Get random data from the device and check it using the FIPS 140
104  tests. If it's less than 64 bits then we let it pass since the
105  sample size is too small to be useful, samples this small are only
106  ever drawn from the generator for use as padding with crypto keys
107  that are always >= 64 bits which will themselves have been checked
108  when they were read, so a problem with the generator will be
109  detected even if we don't check small samples */
110  for( i = 0; i < NO_ENTROPY_FAILURES; i++ )
111  {
112  int status;
113 
114  status = deviceInfoPtr->getRandomFunction( deviceInfoPtr,
115  data, length, messageExtInfo );
116  if( cryptStatusOK( status ) && \
117  ( length < 8 || checkEntropy( data, length ) ) )
118  return( CRYPT_OK );
119  }
120 
121  /* We couldn't get anything that passed the FIPS 140 tests, we can't
122  go any further */
123  zeroise( data, length );
124  DEBUG_DIAG(( "Random data didn't pass FIPS 140 tests after %d "
125  "iterations", NO_ENTROPY_FAILURES ));
126  assert( DEBUG_WARN );
127  return( CRYPT_ERROR_RANDOM );
128  }
129 
130 /* Get a random data block with no zero bytes, for PKCS #1 padding */
131 
132 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
133 static int getRandomNonzero( INOUT DEVICE_INFO *deviceInfoPtr,
134  OUT_BUFFER_FIXED( length ) void *data,
135  IN_LENGTH_SHORT const int length,
137  {
138  BYTE randomBuffer[ 128 + 8 ], *outBuffer = data;
139  int count, iterationCount, status = CRYPT_OK;
140 
141  assert( isWritePtr( deviceInfoPtr, sizeof( DEVICE_INFO ) ) );
142  assert( isWritePtr( data, length ) );
143  assert( messageExtInfo == NULL || \
144  ( isWritePtr( messageExtInfo, \
145  sizeof( MESSAGE_FUNCTION_EXTINFO ) ) ) );
146 
147  REQUIRES( length > 0 && length < MAX_INTLENGTH_SHORT );
148 
149  /* The extraction of data is a little complex because we don't know how
150  much data we'll need (as a rule of thumb it'll be size + ( size / 256 )
151  bytes, but in a worst-case situation we could need to draw out
152  megabytes of data), so we copy out 128 bytes worth at a time (a
153  typical value for a 1K bit key) and keep going until we've filled the
154  output requirements */
155  for( count = 0, iterationCount = 0;
156  count < length && iterationCount < FAILSAFE_ITERATIONS_LARGE;
157  iterationCount++ )
158  {
159  int i;
160 
161  /* Copy as much as we can from the randomness pool. We don't allow
162  the device to be unlocked during this process since we may need
163  it again for further reads */
164  status = getRandomChecked( deviceInfoPtr, randomBuffer, 128, NULL );
165  if( cryptStatusError( status ) )
166  break;
167  for( i = 0; count < length && i < 128; i++ )
168  {
169  if( randomBuffer[ i ] != 0 )
170  outBuffer[ count++ ] = randomBuffer[ i ];
171  }
172  }
173  ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
174  FORALL( i, 0, length, \
175  ( ( BYTE * ) data )[ i ] != 0 );
176  zeroise( randomBuffer, 128 );
177  if( cryptStatusError( status ) )
178  zeroise( data, length );
179  return( status );
180  }
181 
182 /****************************************************************************
183 * *
184 * Get Attributes *
185 * *
186 ****************************************************************************/
187 
188 /* Get a numeric/boolean attribute */
189 
191 int getDeviceAttribute( INOUT DEVICE_INFO *deviceInfoPtr,
192  OUT_INT_Z int *valuePtr,
194  INOUT MESSAGE_FUNCTION_EXTINFO *messageExtInfo )
195  {
196  assert( isWritePtr( deviceInfoPtr, sizeof( DEVICE_INFO ) ) );
197  assert( isWritePtr( valuePtr, sizeof( int ) ) );
198  assert( isWritePtr( messageExtInfo, \
199  sizeof( MESSAGE_FUNCTION_EXTINFO ) ) );
200 
201  REQUIRES( isAttribute( attribute ) || \
202  isInternalAttribute( attribute ) );
203 
204  switch( attribute )
205  {
207  *valuePtr = deviceInfoPtr->errorType;
208  return( CRYPT_OK );
209 
211  *valuePtr = deviceInfoPtr->errorLocus;
212  return( CRYPT_OK );
213 
215  if( deviceInfoPtr->flags & DEVICE_REMOVABLE )
216  {
217  int status;
218 
219  /* If it's a removable device the user could implicitly log
220  out by removing it so we have to perform an explicit
221  check to see whether it's still there */
222  status = deviceInfoPtr->controlFunction( deviceInfoPtr,
223  CRYPT_DEVINFO_LOGGEDIN, NULL, 0, NULL );
224  if( cryptStatusError( status ) )
225  return( status );
226  assert( !isMessageObjectUnlocked( messageExtInfo ) );
227  }
228  *valuePtr = ( deviceInfoPtr->flags & DEVICE_LOGGEDIN ) ? \
229  TRUE : FALSE;
230  return( CRYPT_OK );
231  }
232 
233  retIntError();
234  }
235 
236 /* Get a string attribute */
237 
238 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
239 int getDeviceAttributeS( INOUT DEVICE_INFO *deviceInfoPtr,
242  MESSAGE_FUNCTION_EXTINFO *messageExtInfo )
243  {
244  assert( isWritePtr( deviceInfoPtr, sizeof( DEVICE_INFO ) ) );
245  assert( isWritePtr( msgData, sizeof( MESSAGE_DATA ) ) );
246  assert( isWritePtr( messageExtInfo, \
247  sizeof( MESSAGE_FUNCTION_EXTINFO ) ) );
248 
249  REQUIRES( isAttribute( attribute ) || \
250  isInternalAttribute( attribute ) );
251 
252  switch( attribute )
253  {
255  {
256 #ifdef USE_ERRMSGS
258 
259  switch( deviceInfoPtr->type )
260  {
261  case CRYPT_DEVICE_PKCS11:
262  errorInfo = &deviceInfoPtr->devicePKCS11->errorInfo;
263  break;
264 
266  errorInfo = &deviceInfoPtr->deviceCryptoAPI->errorInfo;
267  break;
268 
269  default:
270  return( exitErrorNotFound( deviceInfoPtr,
272  }
273 
274  if( errorInfo->errorStringLength > 0 )
275  {
276  return( attributeCopy( msgData, errorInfo->errorString,
277  errorInfo->errorStringLength ) );
278  }
279 #endif /* USE_ERRMSGS */
280  return( exitErrorNotFound( deviceInfoPtr,
282  }
283 
284  case CRYPT_DEVINFO_LABEL:
285  if( deviceInfoPtr->label == NULL )
286  return( exitErrorNotFound( deviceInfoPtr,
288  return( attributeCopy( msgData, deviceInfoPtr->label,
289  strlen( deviceInfoPtr->label ) ) );
290 
291  case CRYPT_IATTRIBUTE_RANDOM:
292  if( deviceInfoPtr->getRandomFunction == NULL )
293  return( CRYPT_ERROR_RANDOM );
294  return( getRandomChecked( deviceInfoPtr, msgData->data,
295  msgData->length, messageExtInfo ) );
296 
297  case CRYPT_IATTRIBUTE_RANDOM_NZ:
298  if( deviceInfoPtr->getRandomFunction == NULL )
299  return( CRYPT_ERROR_RANDOM );
300  return( getRandomNonzero( deviceInfoPtr, msgData->data,
301  msgData->length, messageExtInfo ) );
302 
303  case CRYPT_IATTRIBUTE_RANDOM_NONCE:
304  if( deviceInfoPtr->getRandomFunction == NULL )
305  return( CRYPT_ERROR_RANDOM );
306 
307  return( deviceInfoPtr->controlFunction( deviceInfoPtr,
308  CRYPT_IATTRIBUTE_RANDOM_NONCE,
309  msgData->data,
310  msgData->length,
311  messageExtInfo ) );
312 
313  case CRYPT_IATTRIBUTE_TIME:
314  {
315  time_t *timePtr = msgData->data;
316  int status;
317 
318  /* If the device doesn't contain a time source we can't provide
319  time information */
320  if( !( deviceInfoPtr->flags & DEVICE_TIME ) )
321  return( CRYPT_ERROR_NOTAVAIL );
322 
323  /* Get the time from the device */
324  status = deviceInfoPtr->controlFunction( deviceInfoPtr,
325  CRYPT_IATTRIBUTE_TIME,
326  msgData->data,
327  msgData->length, NULL );
328  if( cryptStatusError( status ) )
329  return( status );
330 
331  /* Perform a sanity check on the returned value, if it's too far
332  out then we don't trust it */
333  if( *timePtr <= MIN_TIME_VALUE )
334  {
335  *timePtr = 0;
336  return( CRYPT_ERROR_NOTAVAIL );
337  }
338 
339  return( CRYPT_OK );
340  }
341  }
342 
343  retIntError();
344  }
345 
346 /****************************************************************************
347 * *
348 * Set Attributes *
349 * *
350 ****************************************************************************/
351 
352 /* Set a numeric/boolean attribute */
353 
355 int setDeviceAttribute( INOUT DEVICE_INFO *deviceInfoPtr,
356  IN_INT_Z const int value,
357  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute,
358  MESSAGE_FUNCTION_EXTINFO *messageExtInfo )
359  {
360  assert( isWritePtr( deviceInfoPtr, sizeof( DEVICE_INFO ) ) );
361  assert( isWritePtr( messageExtInfo, \
362  sizeof( MESSAGE_FUNCTION_EXTINFO ) ) );
363 
364  REQUIRES( value >= 0 && value < MAX_INTLENGTH );
365  REQUIRES( isAttribute( attribute ) || \
366  isInternalAttribute( attribute ) );
367 
368  /* Send the control information to the device */
369  return( deviceInfoPtr->controlFunction( deviceInfoPtr, attribute, NULL,
370  value, messageExtInfo ) );
371  }
372 
373 /* Set a string attribute */
374 
376 int setDeviceAttributeS( INOUT DEVICE_INFO *deviceInfoPtr,
377  IN_BUFFER( dataLength ) const void *data,
378  IN_LENGTH const int dataLength,
379  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute,
380  MESSAGE_FUNCTION_EXTINFO *messageExtInfo )
381  {
382  int status;
383 
384  assert( isWritePtr( deviceInfoPtr, sizeof( DEVICE_INFO ) ) );
385  assert( isReadPtr( data, dataLength ) );
386  assert( isWritePtr( messageExtInfo, \
387  sizeof( MESSAGE_FUNCTION_EXTINFO ) ) );
388 
389  REQUIRES( dataLength > 0 && dataLength < MAX_INTLENGTH );
390  REQUIRES( isAttribute( attribute ) || \
391  isInternalAttribute( attribute ) );
392 
393  /* If the user is logging on to the device we have to perform a bit of
394  extra processing */
395  if( attribute == CRYPT_DEVINFO_AUTHENT_USER || \
396  attribute == CRYPT_DEVINFO_AUTHENT_SUPERVISOR )
397  {
398  /* Make sure that a login is actually required for the device */
399  if( !( deviceInfoPtr->flags & DEVICE_NEEDSLOGIN ) )
400  return( exitErrorInited( deviceInfoPtr, attribute ) );
401 
402  /* Send the logon information to the device */
403  status = deviceInfoPtr->controlFunction( deviceInfoPtr, attribute,
404  ( void * ) data, dataLength,
405  messageExtInfo );
406  if( cryptStatusError( status ) )
407  return( status );
408  assert( !isMessageObjectUnlocked( messageExtInfo ) );
409 
410  /* The user has logged in, if the token has a hardware RNG grab 256
411  bits of entropy and send it to the system device. Since we have
412  no idea how good this entropy is (it could be just a DES-based
413  PRNG using a static key or even an LFSR, which some smart cards
414  use) we don't set any entropy quality indication */
415  if( deviceInfoPtr->getRandomFunction != NULL )
416  {
417  BYTE buffer[ 32 + 8 ];
418 
419  status = deviceInfoPtr->getRandomFunction( deviceInfoPtr,
420  buffer, 32, NULL );
421  if( cryptStatusOK( status ) )
422  {
423  MESSAGE_DATA msgData2;
424 
425  setMessageData( &msgData2, buffer, 32 );
427  IMESSAGE_SETATTRIBUTE_S, &msgData2,
428  CRYPT_IATTRIBUTE_ENTROPY );
429  }
430  zeroise( buffer, 32 );
431  }
432 
433  return( CRYPT_OK );
434  }
435 
436  /* Send the control information to the device */
437  return( deviceInfoPtr->controlFunction( deviceInfoPtr, attribute,
438  ( void * ) data, dataLength,
439  messageExtInfo ) );
440  }