1 /****************************************************************************
2 * *
3 * cryptlib Internal API *
4 * Copyright Peter Gutmann 1992-2014 *
5 * *
6 ****************************************************************************/
7
8 /* A generic module that implements a rug under which all problems not
9 solved elsewhere are swept */
10
11 #if defined( INC_ALL )
12 #include "crypt.h"
13 #include "asn1.h"
14 #include "asn1_ext.h"
15 #include "stream.h"
16 #else
17 #include "crypt.h"
18 #include "enc_dec/asn1.h"
19 #include "enc_dec/asn1_ext.h"
20 #include "io/stream.h"
21 #endif /* Compiler-specific includes */
22
23 /* Perform the FIPS-140 statistical checks that are feasible on a byte
24 string. The full suite of tests assumes that an infinite source of
25 values (and time) is available, the following is a scaled-down version
26 used to sanity-check keys and other short random data blocks. Note that
27 this check requires at least 64 bits of data in order to produce useful
28 results */
29
30 CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
checkNontrivialKey(IN_BUFFER (dataLength)const BYTE * data,IN_LENGTH_SHORT_MIN (MIN_KEYSIZE)const int dataLength)31 static BOOLEAN checkNontrivialKey( IN_BUFFER( dataLength ) const BYTE *data,
32 IN_LENGTH_SHORT_MIN( MIN_KEYSIZE ) const int dataLength )
33 {
34 int i;
35
36 for( i = 0; i < dataLength; i++ )
37 {
38 if( !isAlnum( data[ i ] ) )
39 break;
40 }
41 if( i >= dataLength )
42 return( FALSE );
43
44 for( i = 0; i < dataLength - 1; i++ )
45 {
46 const int delta = abs( data[ i ] - data[ i + 1 ] );
47
48 if( delta > 8 )
49 break;
50 }
51 if( i >= dataLength - 1 )
52 return( FALSE );
53
54 return( TRUE );
55 }
56
57 CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
checkEntropy(IN_BUFFER (dataLength)const BYTE * data,IN_LENGTH_SHORT_MIN (MIN_KEYSIZE)const int dataLength)58 BOOLEAN checkEntropy( IN_BUFFER( dataLength ) const BYTE *data,
59 IN_LENGTH_SHORT_MIN( MIN_KEYSIZE ) const int dataLength )
60 {
61 const int delta = ( dataLength < 16 ) ? 1 : 0;
62 int bitCount[ 8 + 8 ], noOnes, i;
63
64 assert( isReadPtr( data, dataLength ) );
65
66 REQUIRES_B( dataLength >= MIN_KEYSIZE && dataLength < MAX_INTLENGTH_SHORT );
67
68 memset( bitCount, 0, sizeof( int ) * 9 );
69 for( i = 0; i < dataLength; i++ )
70 {
71 const int value = byteToInt( data[ i ] );
72
73 bitCount[ value & 3 ]++;
74 bitCount[ ( value >> 2 ) & 3 ]++;
75 bitCount[ ( value >> 4 ) & 3 ]++;
76 bitCount[ ( value >> 6 ) & 3 ]++;
77 }
78
79 /* Monobit test: Make sure that at least 1/4 of the bits are ones and 1/4
80 are zeroes */
81 noOnes = bitCount[ 1 ] + bitCount[ 2 ] + ( 2 * bitCount[ 3 ] );
82 if( noOnes < dataLength * 2 || noOnes > dataLength * 6 )
83 {
84 zeroise( bitCount, 8 * sizeof( int ) );
85 return( FALSE );
86 }
87
88 /* Poker test (almost): Make sure that each bit pair is present at least
89 1/16 of the time. The FIPS 140 version uses 4-bit values but the
90 numer of samples available from the keys is far too small for this so
91 we can only use 2-bit values.
92
93 This isn't precisely 1/16, for short samples (< 128 bits) we adjust
94 the count by one because of the small sample size and for odd-length
95 data we're getting four more samples so the actual figure is slightly
96 less than 1/16 */
97 if( ( bitCount[ 0 ] + delta < dataLength / 2 ) || \
98 ( bitCount[ 1 ] + delta < dataLength / 2 ) || \
99 ( bitCount[ 2 ] + delta < dataLength / 2 ) || \
100 ( bitCount[ 3 ] + delta < dataLength / 2 ) )
101 {
102 zeroise( bitCount, 8 * sizeof( int ) );
103 return( FALSE );
104 }
105
106 zeroise( bitCount, 8 * sizeof( int ) );
107 return( TRUE );
108 }
109
110 /* Copy a string attribute to external storage, with various range checks
111 to follow the cryptlib semantics (these will already have been done by
112 the caller, this is just a backup check). There are two forms for this
113 function, one that takes a MESSAGE_DATA parameter containing all of the
114 result parameters in one place and the other that takes distinct result
115 parameters, typically because they've been passed down through several
116 levels of function call beyond the point where they were in a
117 MESSAGE_DATA */
118
119 CHECK_RETVAL STDC_NONNULL_ARG( ( 3 ) ) \
attributeCopyParams(OUT_BUFFER_OPT (destMaxLength,* destLength)void * dest,IN_LENGTH_SHORT_Z const int destMaxLength,OUT_LENGTH_BOUNDED_SHORT_Z (destMaxLength)int * destLength,IN_BUFFER_OPT (sourceLength)const void * source,IN_LENGTH_SHORT_Z const int sourceLength)120 int attributeCopyParams( OUT_BUFFER_OPT( destMaxLength, \
121 *destLength ) void *dest,
122 IN_LENGTH_SHORT_Z const int destMaxLength,
123 OUT_LENGTH_BOUNDED_SHORT_Z( destMaxLength ) \
124 int *destLength,
125 IN_BUFFER_OPT( sourceLength ) const void *source,
126 IN_LENGTH_SHORT_Z const int sourceLength )
127 {
128 assert( ( dest == NULL && destMaxLength == 0 ) || \
129 ( isWritePtr( dest, destMaxLength ) ) );
130 assert( isWritePtr( destLength, sizeof( int ) ) );
131 assert( ( source == NULL && sourceLength == 0 ) || \
132 isReadPtr( source, sourceLength ) );
133
134 REQUIRES( ( dest == NULL && destMaxLength == 0 ) || \
135 ( dest != NULL && \
136 destMaxLength > 0 && \
137 destMaxLength < MAX_INTLENGTH_SHORT ) );
138 REQUIRES( ( source == NULL && sourceLength == 0 ) || \
139 ( source != NULL && \
140 sourceLength > 0 && \
141 sourceLength < MAX_INTLENGTH_SHORT ) );
142
143 /* Clear return value */
144 *destLength = 0;
145
146 if( sourceLength <= 0 )
147 return( CRYPT_ERROR_NOTFOUND );
148 if( dest != NULL )
149 {
150 assert( isReadPtr( source, sourceLength ) );
151
152 if( sourceLength > destMaxLength || \
153 !isWritePtr( dest, sourceLength ) )
154 return( CRYPT_ERROR_OVERFLOW );
155 memcpy( dest, source, sourceLength );
156 }
157 *destLength = sourceLength;
158
159 return( CRYPT_OK );
160 }
161
162 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
attributeCopy(INOUT MESSAGE_DATA * msgData,IN_BUFFER (attributeLength)const void * attribute,IN_LENGTH_SHORT_Z const int attributeLength)163 int attributeCopy( INOUT MESSAGE_DATA *msgData,
164 IN_BUFFER( attributeLength ) const void *attribute,
165 IN_LENGTH_SHORT_Z const int attributeLength )
166 {
167 assert( isWritePtr( msgData, sizeof( MESSAGE_DATA ) ) );
168 assert( attributeLength == 0 || \
169 isReadPtr( attribute, attributeLength ) );
170
171 REQUIRES( attributeLength >= 0 && \
172 attributeLength < MAX_INTLENGTH_SHORT );
173
174 return( attributeCopyParams( msgData->data, msgData->length,
175 &msgData->length, attribute,
176 attributeLength ) );
177 }
178
179 /* Check whether a given algorithm is available */
180
181 CHECK_RETVAL_BOOL \
algoAvailable(IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo)182 BOOLEAN algoAvailable( IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo )
183 {
184 CRYPT_QUERY_INFO queryInfo;
185
186 REQUIRES_B( cryptAlgo > CRYPT_ALGO_NONE && \
187 cryptAlgo < CRYPT_ALGO_LAST );
188
189 /* Short-circuit check for always-available algorithms. The kernel
190 won't initialise without the symmetric and hash algorithms being
191 present (and SHA-x implies HMAC-SHAx) so it's safe to hardcode them
192 in here */
193 if( cryptAlgo == CRYPT_ALGO_3DES || \
194 cryptAlgo == CRYPT_ALGO_AES || \
195 cryptAlgo == CRYPT_ALGO_SHA1 || \
196 cryptAlgo == CRYPT_ALGO_HMAC_SHA1 || \
197 cryptAlgo == CRYPT_ALGO_SHA2 || \
198 cryptAlgo == CRYPT_ALGO_HMAC_SHA2 || \
199 cryptAlgo == CRYPT_ALGO_RSA )
200 return( TRUE );
201
202 return( cryptStatusOK( krnlSendMessage( SYSTEM_OBJECT_HANDLE,
203 IMESSAGE_DEV_QUERYCAPABILITY, &queryInfo,
204 cryptAlgo ) ) ? TRUE : FALSE );
205 }
206
207 /* For a given hash algorithm pair, check whether the first is stronger than
208 the second. The order is:
209
210 SNAng > SHA2 > SHA-1 > all others */
211
212 CHECK_RETVAL_BOOL \
isStrongerHash(IN_ALGO const CRYPT_ALGO_TYPE algorithm1,IN_ALGO const CRYPT_ALGO_TYPE algorithm2)213 BOOLEAN isStrongerHash( IN_ALGO const CRYPT_ALGO_TYPE algorithm1,
214 IN_ALGO const CRYPT_ALGO_TYPE algorithm2 )
215 {
216 static const CRYPT_ALGO_TYPE algoPrecedence[] = {
217 CRYPT_ALGO_SHAng, CRYPT_ALGO_SHA2, CRYPT_ALGO_SHA1,
218 CRYPT_ALGO_NONE, CRYPT_ALGO_NONE };
219 int algo1index, algo2index;
220
221 REQUIRES_B( isHashAlgo( algorithm1 ) );
222 REQUIRES_B( isHashAlgo( algorithm2 ) );
223
224 /* Find the relative positions on the scale of the two algorithms */
225 for( algo1index = 0;
226 algoPrecedence[ algo1index ] != algorithm1 && \
227 algo1index < FAILSAFE_ARRAYSIZE( algoPrecedence, CRYPT_ALGO_TYPE );
228 algo1index++ )
229 {
230 /* If we've reached an unrated algorithm, it can't be stronger than
231 the other one */
232 if( algoPrecedence[ algo1index ] == CRYPT_ALGO_NONE )
233 return( FALSE );
234 }
235 ENSURES_B( algo1index < FAILSAFE_ARRAYSIZE( algoPrecedence, \
236 CRYPT_ALGO_TYPE ) );
237 for( algo2index = 0;
238 algoPrecedence[ algo2index ] != algorithm2 && \
239 algo2index < FAILSAFE_ARRAYSIZE( algoPrecedence, CRYPT_ALGO_TYPE );
240 algo2index++ )
241 {
242 /* If we've reached an unrated algorithm, it's weaker than the other
243 one */
244 if( algoPrecedence[ algo2index ] == CRYPT_ALGO_NONE )
245 return( TRUE );
246 }
247 ENSURES_B( algo2index < FAILSAFE_ARRAYSIZE( algoPrecedence, \
248 CRYPT_ALGO_TYPE ) );
249
250 /* If the first algorithm has a smaller index than the second, it's a
251 stronger algorithm */
252 return( ( algo1index < algo2index ) ? TRUE : FALSE );
253 }
254
255 /* Return a random small integer. This is used to perform lightweight
256 randomisation of various algorithms in order to make DoS attacks harder.
257 Because of this the values don't have to be cryptographically strong, so
258 all that we do is cache the data from CRYPT_IATTRIBUTE_RANDOM_NONCE and
259 pull out a small integer's worth on each call */
260
261 #define RANDOM_BUFFER_SIZE 16
262
263 CHECK_RETVAL_RANGE_NOERROR( 0, 32767 ) \
getRandomInteger(void)264 int getRandomInteger( void )
265 {
266 static BYTE nonceData[ RANDOM_BUFFER_SIZE + 8 ];
267 static int nonceIndex = 0;
268 int returnValue, status;
269
270 REQUIRES_EXT( !( nonceIndex & 1 ), 0 );
271
272 /* Initialise/reinitialise the nonce data if necessary. See the long
273 coment for getNonce() in system.c for the reason why we don't bail
274 out on error but continue with a lower-quality generator */
275 if( nonceIndex <= 0 )
276 {
277 MESSAGE_DATA msgData;
278
279 setMessageData( &msgData, nonceData, RANDOM_BUFFER_SIZE );
280 status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
281 IMESSAGE_GETATTRIBUTE_S, &msgData,
282 CRYPT_IATTRIBUTE_RANDOM_NONCE );
283 if( cryptStatusError( status ) )
284 return( ( int ) getTime() & 0x7FFF );
285 }
286
287 /* Extract the next random integer value from the buffered data */
288 returnValue = ( byteToInt( nonceData[ nonceIndex ] ) << 8 ) | \
289 byteToInt( nonceData[ nonceIndex + 1 ] );
290 nonceIndex = ( nonceIndex + 2 ) % RANDOM_BUFFER_SIZE;
291 ENSURES_EXT( nonceIndex >= 0 && nonceIndex < RANDOM_BUFFER_SIZE, 0 );
292
293 /* Return the value constrained to lie within the range 0...32767 */
294 return( returnValue & 0x7FFF );
295 }
296
297 /* Map one value to another, used to map values from one representation
298 (e.g. PGP algorithms or HMAC algorithms) to another (cryptlib algorithms
299 or the underlying hash used for the HMAC algorithm) */
300
301 CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 3 ) ) \
mapValue(IN_INT_SHORT_Z const int srcValue,OUT_INT_SHORT_Z int * destValue,IN_ARRAY (mapTblSize)const MAP_TABLE * mapTbl,IN_LENGTH_SHORT const int mapTblSize)302 int mapValue( IN_INT_SHORT_Z const int srcValue,
303 OUT_INT_SHORT_Z int *destValue,
304 IN_ARRAY( mapTblSize ) const MAP_TABLE *mapTbl,
305 IN_LENGTH_SHORT const int mapTblSize )
306 {
307 int i;
308
309 assert( isWritePtr( destValue, sizeof( int ) ) );
310 assert( isReadPtr( mapTbl, mapTblSize * sizeof( MAP_TABLE ) ) );
311
312 REQUIRES( srcValue >= 0 && srcValue < MAX_INTLENGTH_SHORT );
313 REQUIRES( mapTblSize > 0 && mapTblSize < 100 );
314 REQUIRES( mapTbl[ mapTblSize ].source == CRYPT_ERROR );
315
316 /* Clear return value */
317 *destValue = 0;
318
319 /* Convert the hash algorithm into the equivalent HMAC algorithm */
320 for( i = 0; i < mapTblSize && mapTbl[ i ].source != CRYPT_ERROR && \
321 i < FAILSAFE_ITERATIONS_LARGE; i++ )
322 {
323 if( mapTbl[ i ].source == srcValue )
324 {
325 *destValue = mapTbl[ i ].destination;
326
327 return( CRYPT_OK );
328 }
329 }
330 ENSURES( i < mapTblSize );
331
332 return( CRYPT_ERROR_NOTAVAIL );
333 }
334
335 /****************************************************************************
336 * *
337 * Checksum/Hash Functions *
338 * *
339 ****************************************************************************/
340
341 /* Calculate a 16-bit Fletcher-like checksum for a block of data. This
342 isn't quite a pure Fletcher checksum, this isn't a big deal since all we
343 need is consistent results for identical data, the value itself is never
344 communicated externally. In cases where it's used in critical checks
345 it's merely used as a quick pre-check for a full hash-based check, so it
346 doesn't have to be perfect. In addition it's not in any way
347 cryptographically secure for the same reason, there's no particular need
348 for it to be secure. If a requirement for at least some sort of
349 unpredictability did arise then something like Pearson hashing could be
350 substituted transparently */
351
352 RETVAL_RANGE( MAX_ERROR, 0xFFFF ) STDC_NONNULL_ARG( ( 1 ) ) \
checksumData(IN_BUFFER (dataLength)const void * data,IN_DATALENGTH const int dataLength)353 int checksumData( IN_BUFFER( dataLength ) const void *data,
354 IN_DATALENGTH const int dataLength )
355 {
356 const BYTE *dataPtr = data;
357 int sum1 = 1, sum2 = 0, i;
358
359 assert( isReadPtr( data, dataLength ) );
360
361 REQUIRES( data != NULL );
362 REQUIRES( dataLength > 0 && dataLength < MAX_BUFFER_SIZE )
363
364 for( i = 0; i < dataLength; i++ )
365 {
366 sum1 += dataPtr[ i ];
367 sum2 += sum1;
368 }
369
370 #if defined( SYSTEM_16BIT )
371 return( sum2 & 0x7FFF );
372 #else
373 return( ( ( sum2 & 0x7FFF ) << 16 ) | ( sum1 & 0xFFFF ) );
374 #endif /* 16- vs. 32-bit systems */
375 }
376
377 /* Calculate the hash of a block of data. We use SHA-1 because it's the
378 built-in default, but any algorithm will do since we're only using it
379 to transform a variable-length value to a fixed-length one for easy
380 comparison purposes */
381
382 STDC_NONNULL_ARG( ( 1, 3 ) ) \
hashData(OUT_BUFFER_FIXED (hashMaxLength)BYTE * hash,IN_LENGTH_HASH const int hashMaxLength,IN_BUFFER (dataLength)const void * data,IN_DATALENGTH const int dataLength)383 void hashData( OUT_BUFFER_FIXED( hashMaxLength ) BYTE *hash,
384 IN_LENGTH_HASH const int hashMaxLength,
385 IN_BUFFER( dataLength ) const void *data,
386 IN_DATALENGTH const int dataLength )
387 {
388 HASH_FUNCTION_ATOMIC hashFunctionAtomic;
389 BYTE hashBuffer[ CRYPT_MAX_HASHSIZE + 8 ];
390 int hashSize;
391
392 assert( isWritePtr( hash, hashMaxLength ) );
393 assert( hashMaxLength >= 16 && \
394 hashMaxLength <= CRYPT_MAX_HASHSIZE );
395 assert( isReadPtr( data, dataLength ) );
396 assert( dataLength > 0 && dataLength < MAX_BUFFER_SIZE );
397
398 /* Get the hash algorithm information if necessary */
399 getHashAtomicParameters( CRYPT_ALGO_SHA1, 0, &hashFunctionAtomic,
400 &hashSize );
401
402 /* Error handling: If there's a problem, return a zero hash. We use
403 this strategy since this is a void function and so the usual
404 REQUIRES() predicate won't be effective. Note that this can lead to
405 a false-positive match if we're called multiple times with invalid
406 input, in theory we could fill the return buffer with nonce data to
407 ensure that we never get a false-positive match but since this is a
408 should-never-occur condition anyway it's not certain whether forcing
409 a match or forcing a non-match is the preferred behaviour */
410 if( data == NULL || dataLength <= 0 || dataLength >= MAX_BUFFER_SIZE || \
411 hashMaxLength < 16 || hashMaxLength > hashSize || \
412 hashMaxLength > CRYPT_MAX_HASHSIZE || hashFunctionAtomic == NULL )
413 {
414 memset( hash, 0, hashMaxLength );
415 retIntError_Void();
416 }
417
418 /* Hash the data and copy as many bytes as the caller has requested to
419 the output. Typically they'll require only a subset of the full
420 amount since all that we're doing is transforming a variable-length
421 value to a fixed-length value for easy comparison purposes */
422 hashFunctionAtomic( hashBuffer, hashSize, data, dataLength );
423 memcpy( hash, hashBuffer, hashMaxLength );
424 zeroise( hashBuffer, hashSize );
425 }
426
427 /* Compare two blocks of memory in a time-independent manner. This is used
428 to avoid potential timing attacks on memcmp(), which bails out as soon as
429 it finds a mismatch */
430
431 CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1, 2 ) ) \
compareDataConstTime(IN_BUFFER (length)const void * src,IN_BUFFER (length)const void * dest,IN_LENGTH_SHORT const int length)432 BOOLEAN compareDataConstTime( IN_BUFFER( length ) const void *src,
433 IN_BUFFER( length ) const void *dest,
434 IN_LENGTH_SHORT const int length )
435 {
436 const BYTE *srcPtr = src, *destPtr = dest;
437 int value = 0, i;
438
439 assert( isReadPtr( src, length ) );
440 assert( isReadPtr( dest, length ) );
441
442 REQUIRES_B( length > 0 && length < MAX_INTLENGTH_SHORT );
443
444 /* Compare the two values in a time-independent manner */
445 for( i = 0; i < length; i++ )
446 value |= srcPtr[ i ] ^ destPtr[ i ];
447
448 return( !value );
449 }
450
451 /****************************************************************************
452 * *
453 * Stream Export/Import Routines *
454 * *
455 ****************************************************************************/
456
457 /* Export attribute or certificate data to a stream. In theory we would
458 have to export this via a dynbuf and then write it to the stream but we
459 can save some overhead by writing it directly to the stream's buffer.
460
461 Some attributes have a user-defined size (e.g.
462 CRYPT_IATTRIBUTE_RANDOM_NONCE) so we allow the caller to specify an
463 optional length parameter indicating how much of the attribute should be
464 exported */
465
466 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
exportAttr(INOUT STREAM * stream,IN_HANDLE const CRYPT_HANDLE cryptHandle,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attributeType,IN_LENGTH_INDEF const int length)467 static int exportAttr( INOUT STREAM *stream,
468 IN_HANDLE const CRYPT_HANDLE cryptHandle,
469 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attributeType,
470 IN_LENGTH_INDEF const int length )
471 /* Declared as LENGTH_INDEF because SHORT_INDEF
472 doesn't make sense */
473 {
474 MESSAGE_DATA msgData;
475 void *dataPtr = NULL;
476 int attrLength = 0, status;
477
478 assert( isWritePtr( stream, sizeof( STREAM ) ) );
479 assert( sStatusOK( stream ) );
480
481 REQUIRES( cryptHandle == SYSTEM_OBJECT_HANDLE || \
482 isHandleRangeValid( cryptHandle ) );
483 REQUIRES( isAttribute( attributeType ) || \
484 isInternalAttribute( attributeType ) );
485 REQUIRES( ( length == CRYPT_UNUSED ) || \
486 ( length >= 8 && length < MAX_INTLENGTH_SHORT ) );
487
488 /* Get access to the stream buffer if required */
489 if( !sIsNullStream( stream ) )
490 {
491 if( length != CRYPT_UNUSED )
492 {
493 /* It's an explicit-length attribute, make sure that there's
494 enough room left in the stream for it */
495 attrLength = length;
496 status = sMemGetDataBlock( stream, &dataPtr, length );
497 }
498 else
499 {
500 /* It's an implicit-length attribute whose maximum length is
501 defined by the stream size */
502 status = sMemGetDataBlockRemaining( stream, &dataPtr,
503 &attrLength );
504 }
505 if( cryptStatusError( status ) )
506 return( status );
507 }
508
509 /* Export the attribute directly into the stream buffer */
510 setMessageData( &msgData, dataPtr, attrLength );
511 status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
512 &msgData, attributeType );
513 if( cryptStatusOK( status ) )
514 status = sSkip( stream, msgData.length, SSKIP_MAX );
515 return( status );
516 }
517
518 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
exportAttributeToStream(INOUT TYPECAST (STREAM *)void * streamPtr,IN_HANDLE const CRYPT_HANDLE cryptHandle,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attributeType)519 int exportAttributeToStream( INOUT TYPECAST( STREAM * ) void *streamPtr,
520 IN_HANDLE const CRYPT_HANDLE cryptHandle,
521 IN_ATTRIBUTE \
522 const CRYPT_ATTRIBUTE_TYPE attributeType )
523 {
524 assert( isWritePtr( streamPtr, sizeof( STREAM ) ) );
525
526 REQUIRES( isHandleRangeValid( cryptHandle ) );
527 REQUIRES( isAttribute( attributeType ) || \
528 isInternalAttribute( attributeType ) );
529
530 return( exportAttr( streamPtr, cryptHandle, attributeType, \
531 CRYPT_UNUSED ) );
532 }
533
534 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
535 int exportVarsizeAttributeToStream( INOUT TYPECAST( STREAM * ) void *streamPtr,
536 IN_HANDLE const CRYPT_HANDLE cryptHandle,
537 IN_LENGTH_FIXED( CRYPT_IATTRIBUTE_RANDOM_NONCE ) \
538 const CRYPT_ATTRIBUTE_TYPE attributeType,
539 IN_RANGE( 8, 1024 ) \
540 const int attributeDataLength )
541 {
542 assert( isWritePtr( streamPtr, sizeof( STREAM ) ) );
543
544 REQUIRES( cryptHandle == SYSTEM_OBJECT_HANDLE );
545 REQUIRES( attributeType == CRYPT_IATTRIBUTE_RANDOM_NONCE );
546 REQUIRES( attributeDataLength >= 8 && \
547 attributeDataLength <= MAX_ATTRIBUTE_SIZE );
548
549 return( exportAttr( streamPtr, cryptHandle, attributeType,
550 attributeDataLength ) );
551 }
552
553 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
exportCertToStream(INOUT TYPECAST (STREAM *)void * streamPtr,IN_HANDLE const CRYPT_CERTIFICATE cryptCertificate,IN_ENUM (CRYPT_CERTFORMAT)const CRYPT_CERTFORMAT_TYPE certFormatType)554 int exportCertToStream( INOUT TYPECAST( STREAM * ) void *streamPtr,
555 IN_HANDLE const CRYPT_CERTIFICATE cryptCertificate,
556 IN_ENUM( CRYPT_CERTFORMAT ) \
557 const CRYPT_CERTFORMAT_TYPE certFormatType )
558 {
559 MESSAGE_DATA msgData;
560 STREAM *stream = streamPtr;
561 void *dataPtr = NULL;
562 int length = 0, status;
563
564 assert( isWritePtr( stream, sizeof( STREAM ) ) );
565 assert( sStatusOK( stream ) );
566
567 REQUIRES( isHandleRangeValid( cryptCertificate ) );
568 REQUIRES( certFormatType > CRYPT_CERTFORMAT_NONE && \
569 certFormatType < CRYPT_CERTFORMAT_LAST );
570
571 /* Get access to the stream buffer if required */
572 if( !sIsNullStream( stream ) )
573 {
574 status = sMemGetDataBlockRemaining( stream, &dataPtr, &length );
575 if( cryptStatusError( status ) )
576 return( status );
577 }
578
579 /* Export the certificate directly into the stream buffer */
580 setMessageData( &msgData, dataPtr, length );
581 status = krnlSendMessage( cryptCertificate, IMESSAGE_CRT_EXPORT,
582 &msgData, certFormatType );
583 if( cryptStatusOK( status ) )
584 status = sSkip( stream, msgData.length, SSKIP_MAX );
585 return( status );
586 }
587
588 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
importCertFromStream(INOUT void * streamPtr,OUT_HANDLE_OPT CRYPT_CERTIFICATE * cryptCertificate,IN_HANDLE const CRYPT_USER iCryptOwner,IN_ENUM (CRYPT_CERTTYPE)const CRYPT_CERTTYPE_TYPE certType,IN_LENGTH_SHORT_MIN (MIN_CRYPT_OBJECTSIZE)const int certDataLength,IN_FLAGS_Z (KEYMGMT)const int options)589 int importCertFromStream( INOUT void *streamPtr,
590 OUT_HANDLE_OPT CRYPT_CERTIFICATE *cryptCertificate,
591 IN_HANDLE const CRYPT_USER iCryptOwner,
592 IN_ENUM( CRYPT_CERTTYPE ) \
593 const CRYPT_CERTTYPE_TYPE certType,
594 IN_LENGTH_SHORT_MIN( MIN_CRYPT_OBJECTSIZE ) \
595 const int certDataLength,
596 IN_FLAGS_Z( KEYMGMT ) const int options )
597 {
598 MESSAGE_CREATEOBJECT_INFO createInfo;
599 STREAM *stream = streamPtr;
600 void *dataPtr;
601 int status;
602
603 assert( isWritePtr( stream, sizeof( STREAM ) ) );
604 assert( sStatusOK( stream ) );
605 assert( isWritePtr( cryptCertificate, sizeof( CRYPT_CERTIFICATE ) ) );
606
607 REQUIRES( iCryptOwner == DEFAULTUSER_OBJECT_HANDLE || \
608 isHandleRangeValid( iCryptOwner ) );
609 REQUIRES( certType > CRYPT_CERTTYPE_NONE && \
610 certType < CRYPT_CERTTYPE_LAST );
611 REQUIRES( certDataLength >= MIN_CRYPT_OBJECTSIZE && \
612 certDataLength < MAX_INTLENGTH_SHORT );
613 REQUIRES( options >= KEYMGMT_FLAG_NONE && options < KEYMGMT_FLAG_MAX && \
614 ( options & ~KEYMGMT_FLAG_DATAONLY_CERT ) == 0 );
615
616 /* Clear return value */
617 *cryptCertificate = CRYPT_ERROR;
618
619 /* Get access to the stream buffer and skip over the certificate data */
620 status = sMemGetDataBlock( stream, &dataPtr, certDataLength );
621 if( cryptStatusOK( status ) )
622 status = sSkip( stream, certDataLength, SSKIP_MAX );
623 if( cryptStatusError( status ) )
624 return( status );
625
626 /* Import the certificate directly from the stream buffer */
627 setMessageCreateObjectIndirectInfoEx( &createInfo, dataPtr,
628 certDataLength, certType,
629 ( options & KEYMGMT_FLAG_DATAONLY_CERT ) ? \
630 KEYMGMT_FLAG_DATAONLY_CERT : KEYMGMT_FLAG_NONE );
631 createInfo.cryptOwner = iCryptOwner;
632 status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
633 IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
634 &createInfo, OBJECT_TYPE_CERTIFICATE );
635 if( cryptStatusError( status ) )
636 return( status );
637 *cryptCertificate = createInfo.cryptHandle;
638 return( CRYPT_OK );
639 }
640
641 /****************************************************************************
642 * *
643 * Public-key Import Routines *
644 * *
645 ****************************************************************************/
646
647 #ifdef USE_INT_ASN1
648
649 /* Read a public key from an X.509 SubjectPublicKeyInfo record, creating the
650 context necessary to contain it in the process. This is used by a variety
651 of modules including certificate-management, keyset, and crypto device.
652
653 The use of the void * instead of STREAM * is necessary because the STREAM
654 type isn't visible at the global level */
655
656 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
checkKeyLength(INOUT STREAM * stream,const CRYPT_ALGO_TYPE cryptAlgo,const BOOLEAN hasAlgoParameters)657 static int checkKeyLength( INOUT STREAM *stream,
658 const CRYPT_ALGO_TYPE cryptAlgo,
659 const BOOLEAN hasAlgoParameters )
660 {
661 const long startPos = stell( stream );
662 int keyLength, status;
663
664 assert( isWritePtr( stream, sizeof( STREAM ) ) );
665
666 REQUIRES( isPkcAlgo( cryptAlgo ) );
667
668 /* ECC algorithms are a complete mess to handle because of the arbitrary
669 manner in which the algorithm parameters can be represented. To deal
670 with this we skip the parameters and read the public key value, which
671 is a point on a curve stuffed in a variety of creative ways into an
672 BIT STRING. Since this contains two values (the x and y coordinates)
673 we divide the lengths used by two to get an approximation of the
674 nominal key size */
675 if( isEccAlgo( cryptAlgo ) )
676 {
677 readUniversal( stream ); /* Skip algorithm parameters */
678 status = readBitStringHole( stream, &keyLength,
679 MIN_PKCSIZE_ECCPOINT_THRESHOLD,
680 DEFAULT_TAG );
681 if( cryptStatusOK( status ) && isShortECCKey( keyLength / 2 ) )
682 status = CRYPT_ERROR_NOSECURE;
683 if( cryptStatusError( status ) )
684 return( status );
685
686 return( sseek( stream, startPos ) );
687 }
688
689 /* Read the key component that defines the nominal key size, either the
690 first algorithm parameter or the first public-key component */
691 if( hasAlgoParameters )
692 {
693 readSequence( stream, NULL );
694 status = readGenericHole( stream, &keyLength, MIN_PKCSIZE_THRESHOLD,
695 BER_INTEGER );
696 }
697 else
698 {
699 readBitStringHole( stream, NULL, MIN_PKCSIZE_THRESHOLD, DEFAULT_TAG );
700 readSequence( stream, NULL );
701 status = readGenericHole( stream, &keyLength, MIN_PKCSIZE_THRESHOLD,
702 BER_INTEGER );
703 }
704 if( cryptStatusError( status ) )
705 return( status );
706
707 /* Check whether the nominal keysize is within the range defined as
708 being a weak key */
709 if( isShortPKCKey( keyLength ) )
710 return( CRYPT_ERROR_NOSECURE );
711
712 return( sseek( stream, startPos ) );
713 }
714
715 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
iCryptReadSubjectPublicKey(INOUT TYPECAST (STREAM *)void * streamPtr,OUT_HANDLE_OPT CRYPT_CONTEXT * iPubkeyContext,IN_HANDLE const CRYPT_DEVICE iCreatorHandle,const BOOLEAN deferredLoad)716 int iCryptReadSubjectPublicKey( INOUT TYPECAST( STREAM * ) void *streamPtr,
717 OUT_HANDLE_OPT CRYPT_CONTEXT *iPubkeyContext,
718 IN_HANDLE const CRYPT_DEVICE iCreatorHandle,
719 const BOOLEAN deferredLoad )
720 {
721 CRYPT_ALGO_TYPE cryptAlgo;
722 CRYPT_CONTEXT iCryptContext;
723 MESSAGE_CREATEOBJECT_INFO createInfo;
724 MESSAGE_DATA msgData;
725 STREAM *stream = streamPtr;
726 void *spkiPtr DUMMY_INIT_PTR;
727 int spkiLength, length, status;
728
729 assert( isReadPtr( stream, sizeof( STREAM ) ) );
730 assert( isWritePtr( iPubkeyContext, sizeof( CRYPT_CONTEXT ) ) );
731
732 REQUIRES( iCreatorHandle == SYSTEM_OBJECT_HANDLE || \
733 isHandleRangeValid( iCreatorHandle ) );
734
735 /* Clear return value */
736 *iPubkeyContext = CRYPT_ERROR;
737
738 /* Pre-parse the SubjectPublicKeyInfo, both to ensure that it's (at
739 least generally) valid before we go to the extent of creating an
740 encryption context to contain it and to get access to the
741 SubjectPublicKeyInfo data and algorithm information. Because all
742 sorts of bizarre tagging exist due to things like CRMF we read the
743 wrapper as a generic hole rather than the more obvious SEQUENCE */
744 status = getStreamObjectLength( stream, &spkiLength );
745 if( cryptStatusOK( status ) )
746 status = sMemGetDataBlock( stream, &spkiPtr, spkiLength );
747 if( cryptStatusOK( status ) )
748 {
749 status = readGenericHole( stream, NULL,
750 MIN_PKCSIZE_ECCPOINT_THRESHOLD,
751 DEFAULT_TAG );
752 }
753 if( cryptStatusError( status ) )
754 return( status );
755 status = readAlgoIDparam( stream, &cryptAlgo, &length,
756 ALGOID_CLASS_PKC );
757 if( cryptStatusError( status ) )
758 return( status );
759
760 /* Perform minimal key-length checking. We need to do this at this
761 point (rather than having it done implicitly in the
762 SubjectPublicKeyInfo read code) because a too-short key (or at least
763 too-short key data) will result in the kernel rejecting the
764 SubjectPublicKeyInfo before it can be processed, leading to a rather
765 misleading CRYPT_ERROR_BADDATA return status rather the correct
766 CRYPT_ERROR_NOSECURE */
767 status = checkKeyLength( stream, cryptAlgo,
768 ( length > 0 ) ? TRUE : FALSE );
769 if( cryptStatusError( status ) )
770 return( status );
771
772 /* Skip the remainder of the key components in the stream, first the
773 algorithm parameters (if there are any) and then the public-key
774 data */
775 if( length > 0 )
776 readUniversal( stream );
777 status = readUniversal( stream );
778 if( cryptStatusError( status ) )
779 return( status );
780
781 /* Create the public-key context and send the public-key data to it */
782 setMessageCreateObjectInfo( &createInfo, cryptAlgo );
783 status = krnlSendMessage( iCreatorHandle, IMESSAGE_DEV_CREATEOBJECT,
784 &createInfo, OBJECT_TYPE_CONTEXT );
785 if( cryptStatusError( status ) )
786 return( status );
787 iCryptContext = createInfo.cryptHandle;
788 setMessageData( &msgData, spkiPtr, spkiLength );
789 status = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE_S,
790 &msgData, deferredLoad ? \
791 CRYPT_IATTRIBUTE_KEY_SPKI_PARTIAL : \
792 CRYPT_IATTRIBUTE_KEY_SPKI );
793 if( cryptStatusError( status ) )
794 {
795 krnlSendNotifier( iCryptContext, IMESSAGE_DECREFCOUNT );
796 if( status == CRYPT_ARGERROR_STR1 || \
797 status == CRYPT_ARGERROR_NUM1 )
798 {
799 /* If the key data was rejected by the kernel before it got to
800 the SubjectPublicKeyInfo read code (see the comment above)
801 then it'll be rejected with an argument-error code, which we
802 have to convert to a bad-data error before returning it to
803 the caller */
804 return( CRYPT_ERROR_BADDATA );
805 }
806 if( cryptArgError( status ) )
807 {
808 DEBUG_DIAG(( "Public-key load returned argError status" ));
809 assert( DEBUG_WARN );
810 status = CRYPT_ERROR_BADDATA;
811 }
812 return( status );
813 }
814 *iPubkeyContext = iCryptContext;
815 assert( cryptStatusError( \
816 krnlSendMessage( iCryptContext, IMESSAGE_CHECK,
817 NULL, MESSAGE_CHECK_PKC_PRIVATE ) ) );
818 return( CRYPT_OK );
819 }
820 #endif /* USE_INT_ASN1 */
821
822 /****************************************************************************
823 * *
824 * Safe Text-line Read Functions *
825 * *
826 ****************************************************************************/
827
828 #if defined( USE_HTTP ) || defined( USE_BASE64 ) || defined( USE_SSH )
829
830 /* Read a line of text data ending in an EOL. If we get more data than will
831 fit into the read buffer we discard it until we find an EOL. As a
832 secondary concern we want to strip leading, trailing, and repeated
833 whitespace. Leading whitespace is handled by setting the seen-whitespace
834 flag to true initially, this treats any whitespace at the start of the
835 line as superfluous and strips it. Stripping of repeated whitespace is
836 also handled by the seenWhitespace flag, and stripping of trailing
837 whitespace is handled by walking back through any final whitespace once we
838 see the EOL.
839
840 We optionally handle continued lines denoted by the MIME convention of a
841 semicolon as the last non-whitespace character by setting the
842 seenContinuation flag if we see a semicolon as the last non-whitespace
843 character.
844
845 Finally, we also need to handle generic DoS attacks. If we see more than
846 MAX_LINE_LENGTH chars in a line we bail out */
847
848 #define MAX_LINE_LENGTH 4096
849
850 /* The extra level of indirection provided by this function is necessary
851 because the the extended error information isn't accessible from outside
852 the stream code so we can't set it in formatTextLineError() in the usual
853 manner via a retExt(). Instead we call retExtFn() directly and then pass
854 the result down to the stream layer via an ioctl */
855
856 CHECK_RETVAL_ERROR STDC_NONNULL_ARG( ( 1, 2 ) ) \
exitTextLineError(INOUT STREAM * stream,FORMAT_STRING const char * format,const int value1,const int value2,OUT_OPT_BOOL BOOLEAN * localError,IN_ERROR const int status)857 static int exitTextLineError( INOUT STREAM *stream,
858 FORMAT_STRING const char *format,
859 const int value1, const int value2,
860 OUT_OPT_BOOL BOOLEAN *localError,
861 IN_ERROR const int status )
862 {
863 ERROR_INFO errorInfo;
864
865 assert( isWritePtr( stream, sizeof( STREAM ) ) );
866 assert( isReadPtr( format, 4 ) );
867 assert( localError == NULL || \
868 isReadPtr( localError, sizeof( BOOLEAN ) ) );
869
870 REQUIRES( cryptStatusError( status ) );
871
872 /* If the stream doesn't support extended error information, we're
873 done */
874 if( localError == NULL )
875 return( status );
876
877 /* The CRYPT_ERROR_BADDATA is a dummy code used in order to be able to
878 call retExtFn() to format the error string */
879 *localError = TRUE;
880 ( void ) retExtFn( CRYPT_ERROR_BADDATA, &errorInfo, format,
881 value1, value2 );
882 sioctlSetString( stream, STREAM_IOCTL_ERRORINFO, &errorInfo,
883 sizeof( ERROR_INFO ) );
884
885 return( status );
886 }
887
888 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 5 ) ) \
889 int readTextLine( READCHAR_FUNCTION readCharFunction,
890 INOUT void *streamPtr,
891 OUT_BUFFER( lineBufferMaxLen, *lineBufferSize ) \
892 char *lineBuffer,
893 IN_LENGTH_SHORT_MIN( 16 ) const int lineBufferMaxLen,
894 OUT_RANGE( 0, lineBufferMaxLen ) int *lineBufferSize,
895 OUT_OPT_BOOL BOOLEAN *localError,
896 const BOOLEAN allowContinuation )
897 {
898 BOOLEAN seenWhitespace, seenContinuation = FALSE;
899 int totalChars, bufPos = 0;
900
901 assert( isWritePtr( streamPtr, sizeof( STREAM ) ) );
902 assert( isWritePtr( lineBuffer, lineBufferMaxLen ) );
903 assert( isWritePtr( lineBufferSize, sizeof( int ) ) );
904 assert( localError == NULL || \
905 isWritePtr( localError, sizeof( BOOLEAN ) ) );
906
907 REQUIRES( readCharFunction != NULL );
908 REQUIRES( lineBufferMaxLen >= 16 && \
909 lineBufferMaxLen < MAX_INTLENGTH_SHORT );
910
911 /* Clear return values */
912 memset( lineBuffer, 0, min( 16, lineBufferMaxLen ) );
913 *lineBufferSize = 0;
914 if( localError != NULL )
915 *localError = FALSE;
916
917 /* Set the seen-whitespace flag initially to strip leading whitespace */
918 seenWhitespace = TRUE;
919
920 /* Read up to MAX_LINE_LENGTH chars. Anything longer than this is
921 probably a DoS */
922 for( totalChars = 0; totalChars < MAX_LINE_LENGTH; totalChars++ )
923 {
924 int ch, status;
925
926 /* Get the next input character */
927 status = ch = readCharFunction( streamPtr );
928 if( cryptStatusError( status ) )
929 return( status );
930
931 /* If it's an EOL or a continuation marker, strip trailing
932 whitespace */
933 if( ch == '\n' || ( allowContinuation && ch == ';' ) )
934 {
935 /* Strip trailing whitespace. At this point it's all been
936 canonicalised so we don't need to check for anything other
937 than spaces */
938 while( bufPos > 0 && lineBuffer[ bufPos - 1 ] == ' ' )
939 bufPos--;
940 }
941
942 /* Process EOL */
943 if( ch == '\n' )
944 {
945 /* If we've seen a continuation marker, the line continues on
946 the next one */
947 if( seenContinuation )
948 {
949 seenContinuation = FALSE;
950 continue;
951 }
952
953 /* We're done */
954 break;
955 }
956
957 /* Ignore any additional decoration that may accompany EOLs */
958 if( ch == '\r' )
959 continue;
960
961 /* If we're over the maximum buffer size discard any further input
962 until we either hit EOL or exceed the DoS threshold at
963 MAX_LINE_LENGTH */
964 if( bufPos >= lineBufferMaxLen )
965 {
966 /* If we've run off into the weeds (for example we're reading
967 binary data following the text header), bail out */
968 if( !isValidTextChar( ch ) )
969 {
970 return( exitTextLineError( streamPtr, "Invalid character "
971 "0x%02X at position %d", ch,
972 totalChars, localError,
973 CRYPT_ERROR_BADDATA ) );
974 }
975 continue;
976 }
977
978 /* Process whitespace. We can't use isspace() for this because it
979 includes all sorts of extra control characters that we don't want
980 to allow */
981 if( ch == ' ' || ch == '\t' )
982 {
983 if( seenWhitespace )
984 {
985 /* Ignore leading and repeated whitespace */
986 continue;
987 }
988 ch = ' '; /* Canonicalise whitespace */
989 }
990
991 /* Process any remaining chars */
992 if( !isValidTextChar( ch ) )
993 {
994 return( exitTextLineError( streamPtr, "Invalid character "
995 "0x%02X at position %d", ch,
996 totalChars, localError,
997 CRYPT_ERROR_BADDATA ) );
998 }
999 lineBuffer[ bufPos++ ] = intToByte( ch );
1000 ENSURES( bufPos > 0 && bufPos <= totalChars + 1 );
1001 /* The 'totalChars + 1' is because totalChars is the loop
1002 iterator and won't have been incremented yet at this
1003 point */
1004
1005 /* Update the state variables. If the character that we've just
1006 processed was whitespace or if we've seen a continuation
1007 character or we're processing whitespace after having seen a
1008 continuation character (which makes it effectively leading
1009 whitespace to be stripped), remember this */
1010 seenWhitespace = ( ch == ' ' ) ? TRUE : FALSE;
1011 seenContinuation = allowContinuation && \
1012 ( ch == ';' || \
1013 ( seenContinuation && seenWhitespace ) ) ? \
1014 TRUE : FALSE;
1015 }
1016 if( totalChars >= MAX_LINE_LENGTH )
1017 {
1018 return( exitTextLineError( streamPtr, "Text line too long, more "
1019 "than %d characters", MAX_LINE_LENGTH, 0,
1020 localError, CRYPT_ERROR_OVERFLOW ) );
1021 }
1022 *lineBufferSize = bufPos;
1023
1024 return( CRYPT_OK );
1025 }
1026 #endif /* USE_HTTP || USE_BASE64 || USE_SSH */
1027
1028 /****************************************************************************
1029 * *
1030 * Self-test Functions *
1031 * *
1032 ****************************************************************************/
1033
1034 /* Test code for the above functions */
1035
1036 #ifndef NDEBUG
1037
1038 #if defined( USE_HTTP ) || defined( USE_BASE64 ) || defined( USE_SSH )
1039
1040 #include "io/stream.h"
1041
1042 CHECK_RETVAL_RANGE( 0, 255 ) STDC_NONNULL_ARG( ( 1 ) ) \
readCharFunction(INOUT TYPECAST (STREAM *)void * streamPtr)1043 static int readCharFunction( INOUT TYPECAST( STREAM * ) void *streamPtr )
1044 {
1045 STREAM *stream = streamPtr;
1046 BYTE ch;
1047 int status;
1048
1049 assert( isWritePtr( stream, sizeof( STREAM ) ) );
1050
1051 status = sread( stream, &ch, 1 );
1052 return( cryptStatusError( status ) ? status : byteToInt( ch ) );
1053 }
1054
1055 CHECK_RETVAL_BOOL \
IN_BUFFER(dataInLength)1056 static BOOLEAN testReadLine( IN_BUFFER( dataInLength ) char *dataIn,
1057 IN_LENGTH_SHORT_MIN( 8 ) const int dataInLength,
1058 IN_BUFFER( dataOutLength ) char *dataOut,
1059 IN_LENGTH_SHORT_MIN( 1 ) const int dataOutLength,
1060 const BOOLEAN allowContinuation )
1061 {
1062 STREAM stream;
1063 BYTE buffer[ 16 + 8 ];
1064 int length, status;
1065
1066 assert( isReadPtr( dataIn, dataInLength ) );
1067 assert( isReadPtr( dataOut, dataOutLength ) );
1068
1069 REQUIRES( dataInLength >= 8 && dataInLength < MAX_INTLENGTH_SHORT );
1070 REQUIRES( dataOutLength >= 1 && dataOutLength < MAX_INTLENGTH_SHORT );
1071
1072 sMemPseudoConnect( &stream, dataIn, dataInLength );
1073 status = readTextLine( readCharFunction, &stream, buffer, 16,
1074 &length, NULL, allowContinuation );
1075 if( cryptStatusError( status ) )
1076 return( FALSE );
1077 if( length != dataOutLength || memcmp( buffer, dataOut, dataOutLength ) )
1078 return( FALSE );
1079 sMemDisconnect( &stream );
1080
1081 return( TRUE );
1082 }
1083 #endif /* USE_HTTP || USE_BASE64 || USE_SSH */
1084
1085 CHECK_RETVAL_BOOL \
testIntAPI(void)1086 BOOLEAN testIntAPI( void )
1087 {
1088 #if 0
1089 checkNontrivialKey( "\x2E\x19\x76\x57\xDB\x30\xE6\x26", 8 );
1090 checkNontrivialKey( "\x14\xF3\x3C\x5A\xB8\x63\x13\xFB", 8 );
1091 checkNontrivialKey( "\x7B\xE0\xE4\x14\x5C\x7C\x2C\x07", 8 );
1092 checkNontrivialKey( "\xD3\x9C\x16\x37\xAD\x12\x19\xA2", 8 );
1093 checkNontrivialKey( "\x7F\x6B\x30\xAD\x02\x83\x96\xF9", 8 );
1094 checkNontrivialKey( "\x79\x92\xF9\xD1\x75\x43\x56\x87", 8 );
1095 checkNontrivialKey( "\x62\xAF\x14\xCF\x1F\x5F\xA7\xC6", 8 );
1096 checkNontrivialKey( "\xAE\x57\xF3\x63\x45\x03\x2E\x6B", 8 );
1097 checkNontrivialKey( "abcdefgh", 8 );
1098 checkNontrivialKey( "\x01\x23\x45\x67\x89\xAB\xCD\xEF", 8 );
1099 checkNontrivialKey( "\xA5\x5A\xA5\x5A\xA5\x5A\xA5\x5A", 8 );
1100 #endif
1101
1102 /* Test the entropy-check code */
1103 if( !checkEntropy( "\x2E\x19\x76\x57\xDB\x30\xE6\x26", 8 ) || \
1104 !checkEntropy( "\x14\xF3\x3C\x5A\xB8\x63\x13\xFB", 8 ) || \
1105 !checkEntropy( "\x7B\xE0\xE4\x14\x5C\x7C\x2C\x07", 8 ) || \
1106 !checkEntropy( "\xD3\x9C\x16\x37\xAD\x12\x19\xA2", 8 ) || \
1107 !checkEntropy( "\x7F\x6B\x30\xAD\x02\x83\x96\xF9", 8 ) || \
1108 !checkEntropy( "\x79\x92\xF9\xD1\x75\x43\x56\x87", 8 ) || \
1109 !checkEntropy( "\x62\xAF\x14\xCF\x1F\x5F\xA7\xC6", 8 ) || \
1110 !checkEntropy( "\xAE\x57\xF3\x63\x45\x03\x2E\x6B", 8 ) )
1111 return( FALSE );
1112 if( checkEntropy( "\xA5\x5A\xA5\x5A\xA5\x5A\xA5\x5A", 8 ) )
1113 return( FALSE );
1114 if( checkNontrivialKey( "abcdefgh", 8 ) )
1115 return( FALSE );
1116
1117 /* Test the hash algorithm-strength code */
1118 if( isStrongerHash( CRYPT_ALGO_SHA1, CRYPT_ALGO_SHA2 ) || \
1119 !isStrongerHash( CRYPT_ALGO_SHA2, CRYPT_ALGO_SHA1 ) || \
1120 isStrongerHash( CRYPT_ALGO_MD5, CRYPT_ALGO_SHA2 ) || \
1121 !isStrongerHash( CRYPT_ALGO_SHA2, CRYPT_ALGO_MD5 ) )
1122 return( FALSE );
1123
1124 /* Test the checksumming code */
1125 if( checksumData( "12345678", 8 ) != checksumData( "12345678", 8 ) || \
1126 checksumData( "12345678", 8 ) == checksumData( "12345778", 8 ) || \
1127 checksumData( "12345678", 8 ) == checksumData( "12345\xB7" "78", 8 ) || \
1128 checksumData( "12345678", 8 ) == checksumData( "12345\x00" "78", 8 ) )
1129 return( FALSE );
1130
1131 /* Test the text-line read code */
1132 #if defined( USE_HTTP ) || defined( USE_BASE64 ) || defined( USE_SSH )
1133 if( !testReadLine( "abcdefgh\n", 9, "abcdefgh", 8, FALSE ) || \
1134 !testReadLine( "abcdefghijklmnopq\n", 18,
1135 "abcdefghijklmnop", 16, FALSE ) || \
1136 !testReadLine( " abcdefgh\n", 10, "abcdefgh", 8, FALSE ) || \
1137 !testReadLine( "abcdefgh \n", 10, "abcdefgh", 8, FALSE ) || \
1138 !testReadLine( " ab cdefgh \n", 12, "ab cdefgh", 9, FALSE ) || \
1139 !testReadLine( " ab cdefgh \n", 18, "ab cdefgh", 9, FALSE ) )
1140 return( FALSE );
1141 if( !testReadLine( "abcdefgh\r\n", 10, "abcdefgh", 8, FALSE ) || \
1142 !testReadLine( "abcdefgh\r\r\n", 11, "abcdefgh", 8, FALSE ) )
1143 return( FALSE );
1144 if( testReadLine( " \t \n", 8, "", 1, FALSE ) || \
1145 testReadLine( "abc\x12" "efgh\n", 9, "", 1, FALSE ) )
1146 return( FALSE );
1147 if( !testReadLine( "abcdefgh;\nabc\n", 14,
1148 "abcdefgh;", 9, FALSE ) || \
1149 !testReadLine( "abcdefgh;\nabc\n", 14,
1150 "abcdefgh;abc", 12, TRUE ) || \
1151 !testReadLine( "abcdefgh; \n abc\n", 16,
1152 "abcdefgh;abc", 12, TRUE ) || \
1153 !testReadLine( "abcdefgh ; \n abc\n", 17,
1154 "abcdefgh;abc", 12, TRUE ) || \
1155 !testReadLine( "abcdefgh;abc\nabc\n", 17,
1156 "abcdefgh;abc", 12, TRUE ) )
1157 return( FALSE );
1158 if( testReadLine( "abcdefgh;\n", 10, "", 1, TRUE ) || \
1159 testReadLine( "abcdefgh;\n\n", 11, "", 1, TRUE ) || \
1160 testReadLine( "abcdefgh;\n \n", 12, "", 1, TRUE ) )
1161 return( FALSE );
1162 #endif /* USE_HTTP || USE_BASE64 || USE_SSH */
1163
1164 return( TRUE );
1165 }
1166 #endif /* !NDEBUG */
1167