1 /****************************************************************************
2 *																			*
3 *							Stream I/O Functions							*
4 *						Copyright Peter Gutmann 1993-2013					*
5 *																			*
6 ****************************************************************************/
7 
8 #include <stdio.h>
9 #include <stdarg.h>
10 #if defined( INC_ALL )
11   #include "stream_int.h"
12 #else
13   #include "io/stream_int.h"
14 #endif /* Compiler-specific includes */
15 
16 /****************************************************************************
17 *																			*
18 *								Utility Functions							*
19 *																			*
20 ****************************************************************************/
21 
22 /* Sanity-check the stream state */
23 
24 CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
sanityCheck(const STREAM * stream)25 static BOOLEAN sanityCheck( const STREAM *stream )
26 	{
27 	assert( isReadPtr( stream, sizeof( STREAM ) ) );
28 
29 	/* Perform stream type-specific checks */
30 	switch( stream->type )
31 		{
32 		case STREAM_TYPE_NULL:
33 			if( stream->flags )
34 				return( FALSE );
35 			break;
36 
37 		case STREAM_TYPE_MEMORY:
38 			if( stream->flags & STREAM_MFLAG_VFILE )
39 				{
40 				if( stream->flags & ~( STREAM_FLAG_MASK | STREAM_MFLAG_VFILE | \
41 									   STREAM_FFLAG_MASK ) )
42 					return( FALSE );
43 				}
44 			else
45 				{
46 				if( stream->flags & ~STREAM_MFLAG_MASK )
47 					return( FALSE );
48 				}
49 			break;
50 
51 #ifdef USE_FILES
52 		case STREAM_TYPE_FILE:
53 			if( stream->flags & ~STREAM_FFLAG_MASK )
54 				return( FALSE );
55 			break;
56 #endif /* USE_FILES */
57 
58 #ifdef USE_TCP
59 		case STREAM_TYPE_NETWORK:
60 			{
61 			NET_STREAM_INFO *netStream = \
62 					( NET_STREAM_INFO * ) stream->netStreamInfo;
63 
64 			if( netStream->timeout < 0 || netStream->timeout > 300 )
65 				return( FALSE );
66 			break;
67 			}
68 #endif /* USE_TCP */
69 
70 		default:
71 			return( FALSE );
72 		}
73 
74 	/* Null streams have no internal buffer so the buffer position
75 	   indicators aren't used */
76 	if( stream->type == STREAM_TYPE_NULL )
77 		{
78 		/* Null streams, which act as data sinks, have a virtual content-
79 		   length indicator so although the buffer size is zero the buffer
80 		   position values can be nonzero to indicate how much (virtual)
81 		   data they've absorbed */
82 		if( stream->buffer != NULL || stream->bufSize != 0 )
83 			return( FALSE );
84 		if( stream->bufPos < 0 || stream->bufPos > stream->bufEnd ||
85 			stream->bufEnd < 0 || stream->bufEnd >= MAX_BUFFER_SIZE )
86 			return( FALSE );
87 
88 		return( TRUE );
89 		}
90 
91 #ifdef USE_TCP
92 	/* Network streams may be buffered, but if they're not then the internal
93 	   buffer indicators aren't used */
94 	if( stream->type == STREAM_TYPE_NETWORK )
95 		{
96 		NET_STREAM_INFO *netStream = \
97 				( NET_STREAM_INFO * ) stream->netStreamInfo;
98 
99 		/* If it's an unbuffered network stream then all buffer values must
100 		   be zero */
101 		if( stream->buffer == NULL )
102 			{
103 			if( stream->bufPos != 0 || stream->bufSize != 0 || \
104 				stream->bufEnd != 0 )
105 				return( FALSE );
106 			if( netStream->writeBuffer != NULL || \
107 				netStream->writeBufSize != 0 || \
108 				netStream->writeBufEnd != 0 )
109 				return( FALSE );
110 
111 			return( TRUE );
112 			}
113 
114 		/* Network streams have a second buffer used for writes, make sure
115 		   that the write buffer position is within bounds */
116 		if( netStream->writeBuffer == NULL || \
117 			netStream->writeBufSize <= 0 || \
118 			netStream->writeBufSize >= MAX_BUFFER_SIZE )
119 			return( FALSE );
120 		if( netStream->writeBufEnd < 0 || \
121 			netStream->writeBufEnd > netStream->writeBufSize )
122 			return( FALSE );
123 
124 		return( TRUE );
125 		}
126 #endif /* USE_TCP */
127 
128 	/* Everything else requires a buffer, however file streams have to be
129 	   explicitly connected to a buffer after creation so if it's a
130 	   partially-initialised file stream we allow an absent buffer */
131 	if( stream->buffer == NULL )
132 		{
133 		if( stream->type == STREAM_TYPE_FILE && \
134 			!( stream->flags & STREAM_FFLAG_BUFFERSET ) && \
135 			stream->bufPos == 0 && stream->bufEnd == 0 && \
136 			stream->bufSize == 0 )
137 			return( TRUE );
138 
139 		return( FALSE );
140 		}
141 
142 	/* Make sure that the buffer position is within bounds:
143 
144 								 bufSize
145 									|
146 			<------ buffer ------>	v
147 		+---------------------------+
148 		|						|	|
149 		+---------------------------+
150 				^				^
151 				|				|
152 			 bufPos			 bufEnd */
153 	if( stream->bufPos < 0 || stream->bufPos > stream->bufEnd || \
154 		stream->bufEnd < 0 || stream->bufEnd > stream->bufSize || \
155 		stream->bufSize <= 0 || stream->bufSize >= MAX_BUFFER_SIZE )
156 		return( FALSE );
157 
158 #ifdef USE_FILES
159 	/* If it's a file stream make sure that the position within the file
160 	   makes sense */
161 	if( stream->type == STREAM_TYPE_FILE && \
162 		( stream->bufCount < 0 || \
163 		  stream->bufCount >= ( MAX_BUFFER_SIZE / stream->bufSize ) ) )
164 		return( FALSE );
165 #endif /* USE_FILES */
166 
167 	return( TRUE );
168 	}
169 
170 #ifdef USE_FILES
171 
172 /* Refill a stream buffer from backing storage */
173 
174 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
refillStream(INOUT STREAM * stream)175 static int refillStream( INOUT STREAM *stream )
176 	{
177 	int length, status;
178 
179 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
180 
181 	REQUIRES_S( sanityCheck( stream ) );
182 	REQUIRES_S( stream->type == STREAM_TYPE_FILE );
183 	REQUIRES_S( stream->bufPos >= stream->bufEnd || \
184 				( stream->flags & STREAM_FFLAG_POSCHANGED ) );
185 
186 	/* If we've reached EOF we can't refill the stream */
187 	if( stream->flags & STREAM_FFLAG_EOF )
188 		{
189 		/* If partial reads are allowed return an indication of how much
190 		   data we got.  This only works once, after this the persistent
191 		   error state will return an underflow error before we get to this
192 		   point */
193 		stream->status = CRYPT_ERROR_UNDERFLOW;
194 		return( ( stream->flags & STREAM_FLAG_PARTIALREAD ) ? \
195 				OK_SPECIAL : CRYPT_ERROR_UNDERFLOW );
196 		}
197 
198 	/* If we've moved to a different place in the file prepare to get new
199 	   data into the buffer at the new location */
200 	if( ( stream->flags & STREAM_FFLAG_POSCHANGED ) && \
201 		!( stream->flags & STREAM_FFLAG_POSCHANGED_NOSKIP ) )
202 		{
203 		status = fileSeek( stream, stream->bufCount * stream->bufSize );
204 		if( cryptStatusError( status ) )
205 			return( sSetError( stream, status ) );
206 		}
207 
208 	/* Try and read more data into the stream buffer */
209 	status = fileRead( stream, stream->buffer, stream->bufSize, &length );
210 	if( cryptStatusError( status ) )
211 		return( sSetError( stream, status ) );
212 	if( length < stream->bufSize )
213 		{
214 		/* If we got less than we asked for, remember that we're at the end
215 		   of the file */
216 		stream->flags |= STREAM_FFLAG_EOF;
217 		if( length == 0 )
218 			{
219 			/* We ran out of input on an exact buffer boundary, if partial
220 			   reads are allowed return an indication of how much data we
221 			   got.  This only works once, after this the persistent error
222 			   state will return an underflow error before we get to this
223 			   point */
224 			stream->status = CRYPT_ERROR_UNDERFLOW;
225 			return( ( stream->flags & STREAM_FLAG_PARTIALREAD ) ? \
226 					OK_SPECIAL : CRYPT_ERROR_UNDERFLOW );
227 			}
228 		}
229 
230 	/* We've refilled the stream buffer from the file, remember the
231 	   details */
232 	if( !( stream->flags & STREAM_FFLAG_POSCHANGED ) )
233 		stream->bufCount++;
234 	stream->bufEnd = length;
235 	stream->bufPos = 0;
236 	stream->flags &= ~( STREAM_FFLAG_POSCHANGED | \
237 						STREAM_FFLAG_POSCHANGED_NOSKIP );
238 
239 	ENSURES_S( sanityCheck( stream ) );
240 
241 	return( CRYPT_OK );
242 	}
243 
244 /* Empty a stream buffer to backing storage */
245 
246 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
emptyStream(INOUT STREAM * stream,const BOOLEAN forcedFlush)247 static int emptyStream( INOUT STREAM *stream, const BOOLEAN forcedFlush )
248 	{
249 	int status = CRYPT_OK;
250 
251 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
252 
253 	REQUIRES_S( sanityCheck( stream ) );
254 	REQUIRES_S( stream->type == STREAM_TYPE_FILE );
255 
256 	/* If the stream position has been changed, this can only have been from
257 	   a rewind of the stream, in which case we move back to the start of
258 	   the file */
259 	if( stream->flags & STREAM_FFLAG_POSCHANGED )
260 		{
261 		status = fileSeek( stream, 0 );
262 		if( cryptStatusError( status ) )
263 			return( sSetError( stream, status ) );
264 		}
265 
266 	/* Try and write the data to the stream's backing storage */
267 	status = fileWrite( stream, stream->buffer, stream->bufPos );
268 	if( cryptStatusError( status ) )
269 		return( sSetError( stream, status ) );
270 
271 	/* Reset the position-changed flag and, if we've written another buffer
272 	   full of data, remember the details.  If it's a forced flush we leave
273 	   everything as is so that we remember the last write position in the
274 	   file */
275 	stream->flags &= ~STREAM_FFLAG_POSCHANGED;
276 	if( !forcedFlush )
277 		{
278 		stream->bufCount++;
279 		stream->bufPos = 0;
280 		}
281 
282 	ENSURES_S( sanityCheck( stream ) );
283 
284 	return( CRYPT_OK );
285 	}
286 #endif /* USE_FILES */
287 
288 #ifdef VIRTUAL_FILE_STREAM
289 
290 /* Expand a virtual file stream's buffer to make room for new data when it
291    fills up */
292 
293 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
expandVirtualFileStream(INOUT STREAM * stream,IN_LENGTH const int length)294 static int expandVirtualFileStream( INOUT STREAM *stream,
295 									IN_LENGTH const int length )
296 	{
297 	void *newBuffer;
298 	int newSize;
299 
300 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
301 
302 	REQUIRES_S( sanityCheck( stream ) && \
303 				sIsVirtualFileStream( stream ) );
304 	REQUIRES_S( length > 0 && length < MAX_BUFFER_SIZE );
305 
306 	/* If it's a small buffer allocated when we initially read a file and it
307 	   doesn't look like we'll be overflowing a standard-size buffer, just
308 	   expand it up to STREAM_VFILE_BUFSIZE */
309 	if( stream->bufSize < STREAM_VFILE_BUFSIZE && \
310 		stream->bufPos + length < STREAM_VFILE_BUFSIZE - 1024 )
311 		newSize = STREAM_VFILE_BUFSIZE;
312 	else
313 		{
314 		/* Increase the stream buffer size in STREAM_VFILE_BUFSIZE steps */
315 		newSize = stream->bufSize + STREAM_VFILE_BUFSIZE;
316 		}
317 
318 	/* Allocate the buffer and copy the new data across using a safe realloc
319 	   that wipes the original buffer.  If the malloc fails we return
320 	   CRYPT_ERROR_OVERFLOW rather than CRYPT_ERROR_MEMORY since the former
321 	   is more appropriate for the emulated-I/O environment */
322 	if( ( newBuffer = clDynAlloc( "expandVirtualFileStream", \
323 								  stream->bufSize + STREAM_VFILE_BUFSIZE ) ) == NULL )
324 		return( sSetError( stream, CRYPT_ERROR_OVERFLOW ) );
325 	memcpy( newBuffer, stream->buffer, stream->bufEnd );
326 	zeroise( stream->buffer, stream->bufEnd );
327 	clFree( "expandVirtualFileStream", stream->buffer );
328 	stream->buffer = newBuffer;
329 	stream->bufSize = newSize;
330 
331 	ENSURES_S( sanityCheck( stream ) );
332 
333 	return( CRYPT_OK );
334 	}
335 #endif /* VIRTUAL_FILE_STREAM */
336 
337 /****************************************************************************
338 *																			*
339 *							Stream Read Functions							*
340 *																			*
341 ****************************************************************************/
342 
343 /* Read data from a stream */
344 
345 CHECK_RETVAL_RANGE( 0, 0xFF ) STDC_NONNULL_ARG( ( 1 ) ) \
sgetc(INOUT STREAM * stream)346 int sgetc( INOUT STREAM *stream )
347 	{
348 	int ch;
349 
350 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
351 	assert( isReadPtr( stream->buffer, stream->bufSize ) );
352 
353 	/* Check that the input parameters are in order */
354 	if( !isWritePtrConst( stream, sizeof( STREAM ) ) )
355 		retIntError();
356 
357 	REQUIRES_S( sanityCheck( stream ) );
358 	REQUIRES_S( stream->type == STREAM_TYPE_MEMORY || \
359 				stream->type == STREAM_TYPE_FILE );
360 
361 	/* If there's a problem with the stream don't try to do anything */
362 	if( cryptStatusError( stream->status ) )
363 		return( stream->status );
364 
365 	switch( stream->type )
366 		{
367 		case STREAM_TYPE_MEMORY:
368 			/* Read the data from the stream buffer */
369 			if( stream->bufPos >= stream->bufEnd )
370 				return( sSetError( stream, CRYPT_ERROR_UNDERFLOW ) );
371 			ch = byteToInt( stream->buffer[ stream->bufPos++ ] );
372 			break;
373 
374 #ifdef USE_FILES
375 		case STREAM_TYPE_FILE:
376 			REQUIRES_S( stream->flags & STREAM_FFLAG_BUFFERSET );
377 
378 			/* Read the data from the file */
379 			if( stream->bufPos >= stream->bufEnd || \
380 				( stream->flags & STREAM_FFLAG_POSCHANGED ) )
381 				{
382 				int status = refillStream( stream );
383 				if( cryptStatusError( status ) )
384 					return( ( status == OK_SPECIAL ) ? 0 : status );
385 				}
386 			ch = byteToInt( stream->buffer[ stream->bufPos++ ] );
387 			break;
388 #endif /* USE_FILES */
389 
390 		default:
391 			retIntError_Stream( stream );
392 		}
393 
394 	ENSURES_S( sanityCheck( stream ) );
395 
396 	return( ch );
397 	}
398 
399 /* See the comment in stream.h for the use of CHECK_RETVAL rather than
400    CHECK_RETVAL_LENGTH */
401 
402 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
sread(INOUT STREAM * stream,OUT_BUFFER_FIXED (length)void * buffer,IN_LENGTH const int length)403 int sread( INOUT STREAM *stream,
404 		   OUT_BUFFER_FIXED( length ) void *buffer,
405 		   IN_LENGTH const int length )
406 	{
407 	int status;
408 
409 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
410 	assert( stream->type == STREAM_TYPE_NETWORK || \
411 			isReadPtr( stream->buffer, stream->bufSize ) );
412 	assert( isWritePtr( buffer, length ) );
413 
414 	/* Check that the input parameters are in order */
415 	if( !isWritePtrConst( stream, sizeof( STREAM ) ) )
416 		retIntError();
417 	if( !isWritePtr( buffer, length ) )
418 		retIntError_Stream( stream );
419 
420 	REQUIRES_S( sanityCheck( stream ) );
421 	REQUIRES_S( stream->type == STREAM_TYPE_MEMORY || \
422 				stream->type == STREAM_TYPE_FILE || \
423 				stream->type == STREAM_TYPE_NETWORK );
424 	REQUIRES_S( length > 0 && length < MAX_BUFFER_SIZE );
425 
426 	/* If there's a problem with the stream don't try to do anything */
427 	if( cryptStatusError( stream->status ) )
428 		return( stream->status );
429 
430 	switch( stream->type )
431 		{
432 		case STREAM_TYPE_MEMORY:
433 			{
434 			int localLength = length;
435 
436 #ifdef VIRTUAL_FILE_STREAM
437 			/* If partial reads are allowed return whatever's left in the
438 			   stream buffer.  This only occurs for virtual file streams
439 			   that have been translated into memory streams */
440 			if( stream->flags & STREAM_FLAG_PARTIALREAD )
441 				{
442 				REQUIRES_S( sIsVirtualFileStream( stream ) );
443 
444 				localLength = stream->bufEnd - stream->bufPos;
445 				if( localLength > length )
446 					localLength = length;
447 				}
448 #endif /* VIRTUAL_FILE_STREAM */
449 #if defined( USE_TCP ) && !defined( NDEBUG )
450 			if( sIsPseudoHTTPRawStream( stream ) )
451 				{
452 				NET_STREAM_INFO *netStream = \
453 						( NET_STREAM_INFO * ) stream->netStreamInfo;
454 				const STM_READ_FUNCTION readFunction = \
455 						FNPTR_GET( netStream->readFunction );
456 				int bytesRead;
457 
458 				REQUIRES( readFunction != NULL );
459 
460 				status = readFunction( stream, buffer, length, &bytesRead );
461 				break;
462 				}
463 			if( sIsPseudoHTTPStream( stream ) )
464 				{
465 				HTTP_DATA_INFO *httpDataInfo = ( HTTP_DATA_INFO * ) buffer;
466 
467 				REQUIRES_S( localLength == sizeof( HTTP_DATA_INFO ) );
468 
469 				/* Pseudo-streams using HTTP transport have special
470 				   requirements since the output buffer isn't a direct
471 				   pointer to the buffer but an HTTP_DATA_INFO containing
472 				   information on the HTTP stream, so we have to copy
473 				   information across to/from the HTTP_DATA_INFO */
474 				buffer = httpDataInfo->buffer;
475 				httpDataInfo->bytesAvail = stream->bufEnd;
476 				localLength = stream->bufEnd;
477 				}
478 #endif /* USE_TCP && !NDEBUG */
479 
480 			/* Read the data from the stream buffer */
481 			if( stream->bufPos + localLength > stream->bufEnd )
482 				{
483 				memset( buffer, 0, min( 16, length ) );	/* Clear output buffer */
484 				return( sSetError( stream, CRYPT_ERROR_UNDERFLOW ) );
485 				}
486 			ENSURES_S( rangeCheckZ( stream->bufPos, localLength,
487 									stream->bufEnd ) );
488 			memcpy( buffer, stream->buffer + stream->bufPos, localLength );
489 			stream->bufPos += localLength;
490 
491 			/* Usually reads are atomic so we just return an all-OK
492 			   indicator, however if we're performing partial reads we need
493 			   to return an exact byte count */
494 			status = ( stream->flags & STREAM_FLAG_PARTIALREAD ) ? \
495 					 localLength : CRYPT_OK;
496 #ifndef NDEBUG
497 			if( sIsPseudoStream( stream ) )
498 				{
499 				/* Pseudo-streams are memory streams emulating other stream
500 				   types, so we need to return a byte count */
501 				status = localLength;
502 				}
503 #endif /* !NDEBUG */
504 			break;
505 			}
506 
507 #ifdef USE_FILES
508 		case STREAM_TYPE_FILE:
509 			{
510 			BYTE *bufPtr = buffer;
511 			int dataLength, bytesCopied = 0, iterationCount;
512 
513 			REQUIRES_S( stream->flags & STREAM_FFLAG_BUFFERSET );
514 
515 			/* Read the data from the file */
516 			for( dataLength = length, iterationCount = 0;
517 				 dataLength > 0 && iterationCount < FAILSAFE_ITERATIONS_LARGE;
518 				 iterationCount++ )
519 				{
520 				const int oldDataLength = dataLength;
521 				int bytesToCopy;
522 
523 				/* If the stream buffer is empty try and refill it */
524 				if( stream->bufPos >= stream->bufEnd || \
525 					( stream->flags & STREAM_FFLAG_POSCHANGED ) )
526 					{
527 					status = refillStream( stream );
528 					if( cryptStatusError( status ) )
529 						return( ( status == OK_SPECIAL ) ? \
530 								bytesCopied : status );
531 					}
532 
533 				/* Copy as much data as we can out of the stream buffer */
534 				bytesToCopy = min( dataLength, \
535 								   stream->bufEnd - stream->bufPos );
536 				ENSURES_S( rangeCheckZ( stream->bufPos, bytesToCopy,
537 										stream->bufEnd ) );
538 				memcpy( bufPtr, stream->buffer + stream->bufPos,
539 						bytesToCopy );
540 				stream->bufPos += bytesToCopy;
541 				bufPtr += bytesToCopy;
542 				bytesCopied += bytesToCopy;
543 				dataLength -= bytesToCopy;
544 				ENSURES_S( dataLength < oldDataLength );
545 				}
546 			ENSURES_S( iterationCount < FAILSAFE_ITERATIONS_LARGE );
547 
548 			/* Usually reads are atomic so we just return an all-OK
549 			   indicator, however if we're performing partial reads we need
550 			   to return an exact byte count */
551 			status = ( stream->flags & STREAM_FLAG_PARTIALREAD ) ? \
552 					 bytesCopied : CRYPT_OK;
553 			break;
554 			}
555 #endif /* USE_FILES */
556 
557 #ifdef USE_TCP
558 		case STREAM_TYPE_NETWORK:
559 			{
560 			NET_STREAM_INFO *netStream = \
561 					( NET_STREAM_INFO * ) stream->netStreamInfo;
562 			const STM_READ_FUNCTION readFunction = \
563 					FNPTR_GET( netStream->readFunction );
564 			int bytesRead;
565 
566 			REQUIRES_S( netStream->protocol != STREAM_PROTOCOL_HTTP || \
567 						( netStream->protocol == STREAM_PROTOCOL_HTTP && \
568 						  length == sizeof( HTTP_DATA_INFO ) ) );
569 			REQUIRES_S( readFunction != NULL );
570 
571 			/* Read the data from the network.  Reads are normally atomic
572 			   but if the partial-write flag is set can be restarted after
573 			   a timeout */
574 			status = readFunction( stream, buffer, length, &bytesRead );
575 			if( cryptStatusError( status ) )
576 				{
577 				/* If the lower-level code has indicated that the error
578 				   condition is fatal, make it persistent for the stream */
579 				if( cryptStatusError( netStream->persistentStatus ) )
580 					stream->status = netStream->persistentStatus;
581 
582 				/* If it's not a special-case CRYPT_ERROR_COMPLETE status,
583 				   exit.  We don't make the error persistent since unlike
584 				   memory or file stream reads, most errors on network reads
585 				   are recoverable */
586 				if( status != CRYPT_ERROR_COMPLETE )
587 					return( status );
588 
589 				/* If we get a CRYPT_ERROR_COMPLETE status this means that
590 				   the other side has closed the connection.  This status is
591 				   returned when there are intermediate protocol layers such
592 				   as HTTP or tunnelling over a cryptlib session involved.
593 				   When this occurs we update the stream state and map the
594 				   status to a standard read error.  The exact code to
595 				   return here is a bit uncertain, it isn't specifically a
596 				   read error because either the other side is allowed to
597 				   close the connection after it's said its bit (and so it's
598 				   not a read error), or it has to perform a
599 				   cryptographically protected close (in which case any
600 				   non-OK status indicates a problem).  The most sensible
601 				   status is probably a read error */
602 				netStream->nFlags |= STREAM_NFLAG_LASTMSGR;
603 				return( CRYPT_ERROR_READ );
604 				}
605 			if( bytesRead < length && \
606 				!( ( stream->flags & STREAM_FLAG_PARTIALREAD ) || \
607 				   ( netStream->nFlags & STREAM_NFLAG_ENCAPS ) ) )
608 				{
609 				/* If we didn't read all of the data and partial reads
610 				   aren't allowed report a read timeout.  The situation
611 				   for HTTP streams is a bit special because what we're
612 				   sending to the read function is an HTTP_DATA_INFO
613 				   structure so we have to extract the actual length
614 				   information from that */
615 				if( netStream->protocol == STREAM_PROTOCOL_HTTP )
616 					{
617 #ifdef USE_ERRMSGS
618 					const HTTP_DATA_INFO *httpDataInfo = \
619 									( HTTP_DATA_INFO * ) buffer;
620 #endif /* USE_ERRMSGS */
621 
622 					retExt( CRYPT_ERROR_TIMEOUT,
623 							( CRYPT_ERROR_TIMEOUT, NETSTREAM_ERRINFO,
624 							  "Read timed out with %d of %d bytes read",
625 							  httpDataInfo->bytesTransferred,
626 							  httpDataInfo->bytesAvail ) );
627 					}
628 				retExt( CRYPT_ERROR_TIMEOUT,
629 						( CRYPT_ERROR_TIMEOUT, NETSTREAM_ERRINFO,
630 						  "Read timed out with %d of %d bytes read",
631 						  bytesRead, length ) );
632 				}
633 
634 			/* This is an ugly case where we have to follow the Posix
635 			   semantics of returning a read-bytes count as the return
636 			   status rather than a by-reference parameter.  If we didn't
637 			   do this then every trivial memory-stream read would need to
638 			   pass in a dummy parameter for the read-byte-count value just
639 			   to handle the one or two calls to a network stream read that
640 			   needs to return a length */
641 			status = bytesRead;
642 			break;
643 			}
644 #endif /* USE_TCP */
645 
646 		default:
647 			retIntError_Stream( stream );
648 		}
649 
650 	ENSURES_S( sanityCheck( stream ) );
651 
652 	return( status );
653 	}
654 
655 /****************************************************************************
656 *																			*
657 *							Stream Write Functions							*
658 *																			*
659 ****************************************************************************/
660 
661 /* Write data to a stream */
662 
663 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
sputc(INOUT STREAM * stream,IN_BYTE const int ch)664 int sputc( INOUT STREAM *stream, IN_BYTE const int ch )
665 	{
666 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
667 	assert( stream->type == STREAM_TYPE_NULL || \
668 			isWritePtr( stream->buffer, stream->bufSize ) );
669 
670 	/* Check that the input parameters are in order */
671 	if( !isWritePtrConst( stream, sizeof( STREAM ) ) )
672 		retIntError();
673 
674 	REQUIRES_S( sanityCheck( stream ) );
675 	REQUIRES_S( stream->type == STREAM_TYPE_NULL || \
676 				stream->type == STREAM_TYPE_MEMORY || \
677 				stream->type == STREAM_TYPE_FILE );
678 	REQUIRES_S( !( stream->flags & STREAM_FLAG_READONLY ) );
679 	REQUIRES( ch >= 0 && ch <= 0xFF );
680 
681 	/* If there's a problem with the stream don't try to do anything until
682 	   the error is cleared */
683 	if( cryptStatusError( stream->status ) )
684 		return( stream->status );
685 
686 	/* If this is a pseudo-stream then writes are discarded */
687 #ifndef NDEBUG
688 	if( sIsPseudoStream( stream ) )
689 		return( CRYPT_OK );
690 #endif /* !NDEBUG */
691 
692 	switch( stream->type )
693 		{
694 		case STREAM_TYPE_NULL:
695 			/* It's a null stream, just record the write and return */
696 			stream->bufPos++;
697 			if( stream->bufEnd < stream->bufPos )
698 				stream->bufEnd = stream->bufPos;
699 			break;
700 
701 		case STREAM_TYPE_MEMORY:
702 			/* Write the data to the stream buffer */
703 			if( stream->bufPos >= stream->bufSize )
704 				{
705 #ifdef VIRTUAL_FILE_STREAM
706 				if( sIsVirtualFileStream( stream ) )
707 					{
708 					int status;
709 
710 					status = expandVirtualFileStream( stream, 1 );
711 					if( cryptStatusError( status ) )
712 						return( status );
713 					}
714 				else
715 #endif /* VIRTUAL_FILE_STREAM */
716 					return( sSetError( stream, CRYPT_ERROR_OVERFLOW ) );
717 				}
718 			stream->buffer[ stream->bufPos++ ] = intToByte( ch );
719 			if( stream->bufEnd < stream->bufPos )
720 				stream->bufEnd = stream->bufPos;
721 #ifdef VIRTUAL_FILE_STREAM
722 			if( sIsVirtualFileStream( stream ) )
723 				{
724 				/* This is a memory stream emulating a file stream, set the
725 				   dirty bit */
726 				stream->flags |= STREAM_FLAG_DIRTY;
727 				}
728 #endif /* VIRTUAL_FILE_STREAM */
729 			break;
730 
731 #ifdef USE_FILES
732 		case STREAM_TYPE_FILE:
733 			REQUIRES_S( stream->flags & STREAM_FFLAG_BUFFERSET );
734 
735 			/* Write the data to the file */
736 			if( stream->bufPos >= stream->bufSize )
737 				{
738 				int status;
739 
740 				status = emptyStream( stream, FALSE );
741 				if( cryptStatusError( status ) )
742 					return( status );
743 				}
744 			stream->buffer[ stream->bufPos++ ] = intToByte( ch );
745 			stream->flags |= STREAM_FLAG_DIRTY;
746 			break;
747 #endif /* USE_FILES */
748 
749 		default:
750 			retIntError_Stream( stream );
751 		}
752 
753 	ENSURES_S( sanityCheck( stream ) );
754 
755 	return( CRYPT_OK );
756 	}
757 
758 /* See the comment in stream.h for the use of CHECK_RETVAL rather than
759    CHECK_RETVAL_LENGTH */
760 
761 RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
swrite(INOUT STREAM * stream,IN_BUFFER (length)const void * buffer,IN_LENGTH const int length)762 int swrite( INOUT STREAM *stream,
763 		    IN_BUFFER( length ) const void *buffer,
764 			IN_LENGTH const int length )
765 	{
766 	int status;
767 
768 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
769 	assert( stream->type == STREAM_TYPE_NULL || \
770 			stream->type == STREAM_TYPE_NETWORK || \
771 			isWritePtr( stream->buffer, stream->bufSize ) );
772 	assert( isReadPtr( buffer, length ) );
773 
774 	/* Check that the input parameters are in order */
775 	if( !isWritePtrConst( stream, sizeof( STREAM ) ) )
776 		retIntError();
777 	if( !isReadPtr( buffer, length ) )
778 		retIntError_Stream( stream );
779 
780 	REQUIRES_S( sanityCheck( stream ) );
781 	REQUIRES_S( stream->type == STREAM_TYPE_NULL || \
782 				stream->type == STREAM_TYPE_MEMORY || \
783 				stream->type == STREAM_TYPE_FILE || \
784 				stream->type == STREAM_TYPE_NETWORK );
785 	REQUIRES_S( length > 0 && length < MAX_BUFFER_SIZE );
786 	REQUIRES_S( !( stream->flags & STREAM_FLAG_READONLY ) );
787 
788 	/* If there's a problem with the stream don't try to do anything until
789 	   the error is cleared */
790 	if( cryptStatusError( stream->status ) )
791 		return( stream->status );
792 
793 	/* If this is a pseudo-stream then writes are discarded */
794 #ifndef NDEBUG
795 	if( sIsPseudoStream( stream ) )
796 		return( CRYPT_OK );
797 #endif /* !NDEBUG */
798 
799 	switch( stream->type )
800 		{
801 		case STREAM_TYPE_NULL:
802 			/* It's a null stream, just record the write and return */
803 			stream->bufPos += length;
804 			if( stream->bufEnd < stream->bufPos )
805 				stream->bufEnd = stream->bufPos;
806 			status = CRYPT_OK;
807 			break;
808 
809 		case STREAM_TYPE_MEMORY:
810 			/* Write the data to the stream buffer */
811 			if( stream->bufPos + length > stream->bufSize )
812 				{
813 #ifdef VIRTUAL_FILE_STREAM
814 				if( sIsVirtualFileStream( stream ) )
815 					{
816 					status = expandVirtualFileStream( stream, length );
817 					if( cryptStatusError( status ) )
818 						return( status );
819 					}
820 				else
821 #endif /* VIRTUAL_FILE_STREAM */
822 					return( sSetError( stream, CRYPT_ERROR_OVERFLOW ) );
823 				}
824 			ENSURES_S( rangeCheckZ( stream->bufPos, length,
825 									stream->bufSize ) );
826 			memcpy( stream->buffer + stream->bufPos, buffer, length );
827 			stream->bufPos += length;
828 			if( stream->bufEnd < stream->bufPos )
829 				stream->bufEnd = stream->bufPos;
830 #ifdef VIRTUAL_FILE_STREAM
831 			if( sIsVirtualFileStream( stream ) )
832 				{
833 				/* This is a memory stream emulating a file stream, set the
834 				   dirty bit */
835 				stream->flags |= STREAM_FLAG_DIRTY;
836 				}
837 #endif /* VIRTUAL_FILE_STREAM */
838 			status = CRYPT_OK;
839 			break;
840 
841 #ifdef USE_FILES
842 		case STREAM_TYPE_FILE:
843 			{
844 			const BYTE *bufPtr = buffer;
845 			int dataLength, iterationCount;
846 
847 			REQUIRES_S( stream->flags & STREAM_FFLAG_BUFFERSET );
848 
849 			/* Write the data to the file */
850 			for( dataLength = length, iterationCount = 0;
851 				 dataLength > 0 && iterationCount < FAILSAFE_ITERATIONS_LARGE;
852 				 iterationCount++ )
853 				{
854 				const int bytesToCopy = \
855 						min( dataLength, stream->bufSize - stream->bufPos );
856 
857 				if( bytesToCopy > 0 )
858 					{
859 					ENSURES_S( rangeCheckZ( stream->bufPos, bytesToCopy,
860 											stream->bufSize ) );
861 					memcpy( stream->buffer + stream->bufPos, bufPtr,
862 							bytesToCopy );
863 					stream->bufPos += bytesToCopy;
864 					bufPtr += bytesToCopy;
865 					dataLength -= bytesToCopy;
866 					}
867 				if( stream->bufPos >= stream->bufSize )
868 					{
869 					status = emptyStream( stream, FALSE );
870 					if( cryptStatusError( status ) )
871 						return( status );
872 					}
873 				}
874 			ENSURES_S( iterationCount < FAILSAFE_ITERATIONS_LARGE );
875 			stream->flags |= STREAM_FLAG_DIRTY;
876 			status = CRYPT_OK;
877 			break;
878 			}
879 #endif /* USE_FILES */
880 
881 #ifdef USE_TCP
882 		case STREAM_TYPE_NETWORK:
883 			{
884 			NET_STREAM_INFO *netStream = \
885 					( NET_STREAM_INFO * ) stream->netStreamInfo;
886 			const STM_WRITE_FUNCTION writeFunction = \
887 					FNPTR_GET( netStream->writeFunction );
888 			int bytesWritten;
889 
890 			REQUIRES_S( netStream->protocol != STREAM_PROTOCOL_HTTP || \
891 						( netStream->protocol == STREAM_PROTOCOL_HTTP && \
892 						  length == sizeof( HTTP_DATA_INFO ) ) );
893 			REQUIRES_S( writeFunction != NULL );
894 
895 			/* Write the data to the network.  Writes are normally atomic
896 			   but if the partial-write flag is set can be restarted after
897 			   a timeout */
898 			status = writeFunction( stream, buffer, length, &bytesWritten );
899 			if( cryptStatusError( status ) )
900 				{
901 				/* If the lower-level code has indicated that the error
902 				   condition is fatal, make it persistent for the stream */
903 				if( cryptStatusError( netStream->persistentStatus ) )
904 					stream->status = netStream->persistentStatus;
905 
906 				return( status );
907 				}
908 			if( bytesWritten < length && \
909 				!( stream->flags & STREAM_FLAG_PARTIALWRITE ) )
910 				{
911 				/* If we didn't write all of the data and partial writes
912 				   aren't allowed report a write timeout.  The situation
913 				   for HTTP streams is a bit special because what we're
914 				   sending to the write function is an HTTP_DATA_INFO
915 				   structure so we have to extract the actual length
916 				   information from that */
917 				if( netStream->protocol == STREAM_PROTOCOL_HTTP )
918 					{
919 #ifdef USE_ERRMSGS
920 					const HTTP_DATA_INFO *httpDataInfo = \
921 									( HTTP_DATA_INFO * ) buffer;
922 #endif /* USE_ERRMSGS */
923 
924 					retExt( CRYPT_ERROR_TIMEOUT,
925 							( CRYPT_ERROR_TIMEOUT, NETSTREAM_ERRINFO,
926 							  "Write timed out with %d of %d bytes written",
927 							  httpDataInfo->bytesTransferred,
928 							  httpDataInfo->bufSize ) );
929 					}
930 				retExt( CRYPT_ERROR_TIMEOUT,
931 						( CRYPT_ERROR_TIMEOUT, NETSTREAM_ERRINFO,
932 						  "Write timed out with %d of %d bytes written",
933 						  bytesWritten, length ) );
934 				}
935 			status = bytesWritten;
936 			break;
937 			}
938 #endif /* USE_TCP */
939 
940 		default:
941 			retIntError_Stream( stream );
942 		}
943 
944 	ENSURES_S( sanityCheck( stream ) );
945 
946 	return( status );
947 	}
948 
949 #ifdef USE_FILES
950 
951 /* Commit data in a stream to backing storage */
952 
953 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
sflush(INOUT STREAM * stream)954 int sflush( INOUT STREAM *stream )
955 	{
956 	int status = CRYPT_OK, flushStatus;
957 
958 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
959 	assert( isReadPtr( stream->buffer, stream->bufSize ) );
960 
961 	/* Check that the input parameters are in order */
962 	if( !isWritePtrConst( stream, sizeof( STREAM ) ) )
963 		retIntError();
964 
965 	if( !isReadPtr( stream->buffer, stream->bufSize ) )
966 		retIntError_Stream( stream );
967 
968 	REQUIRES_S( sanityCheck( stream ) && \
969 				( ( stream->flags & STREAM_FFLAG_BUFFERSET ) || \
970 				  sIsVirtualFileStream( stream ) ) );
971 	REQUIRES_S( stream->type == STREAM_TYPE_FILE || \
972 				sIsVirtualFileStream( stream ) );
973 	REQUIRES_S( !( stream->flags & STREAM_FLAG_READONLY ) );
974 
975 	/* If there's a problem with the stream don't try to do anything until
976 	   the error is cleared */
977 	if( cryptStatusError( stream->status ) )
978 		return( stream->status );
979 
980 	/* If the data in the stream buffer is unchanged there's nothing to do */
981 	if( !( stream->flags & STREAM_FLAG_DIRTY ) )
982 		return( CRYPT_OK );
983 
984 	/* If there's data still in the stream buffer and it's not a virtual
985 	   file stream that's handled via a memory stream (for which the data
986 	   is committed in an atomic operation when the file is flushed), write
987 	   it to disk.  If there's an error at this point we still try and flush
988 	   whatever data we have to disk so we don't bail out immediately if
989 	   there's a problem */
990 	if( stream->bufPos > 0 && !sIsVirtualFileStream( stream ) )
991 		status = emptyStream( stream, TRUE );
992 
993 	/* Commit the data */
994 	flushStatus = fileFlush( stream );
995 	stream->flags &= ~STREAM_FLAG_DIRTY;
996 
997 	return( cryptStatusOK( status ) ? flushStatus : status );
998 	}
999 #endif /* USE_FILES */
1000 
1001 /****************************************************************************
1002 *																			*
1003 *								Meta-data Functions							*
1004 *																			*
1005 ****************************************************************************/
1006 
1007 /* Set/clear the error status of a stream.  sSetError() returns the error
1008    status that it's passed so that it can be called using
1009    'return( sSetError( stream, status ) );' */
1010 
1011 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
sSetError(INOUT STREAM * stream,IN_ERROR const int status)1012 int sSetError( INOUT STREAM *stream, IN_ERROR const int status )
1013 	{
1014 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
1015 
1016 	REQUIRES_S( cryptStatusError( status ) );
1017 
1018 	/* Check that the input parameters are in order */
1019 	if( !isWritePtrConst( stream, sizeof( STREAM ) ) )
1020 		retIntError();
1021 
1022 	/* If there's already an error status set don't try and override it */
1023 	if( cryptStatusError( stream->status ) )
1024 		return( stream->status );
1025 
1026 	stream->status = status;
1027 
1028 	return( status );
1029 	}
1030 
1031 STDC_NONNULL_ARG( ( 1 ) ) \
sClearError(INOUT STREAM * stream)1032 void sClearError( INOUT STREAM *stream )
1033 	{
1034 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
1035 
1036 	/* Check that the input parameters are in order */
1037 	if( !isWritePtrConst( stream, sizeof( STREAM ) ) )
1038 		retIntError_Void();
1039 
1040 	stream->status = CRYPT_OK;
1041 	}
1042 
1043 /* Determine whether a stream is a null stream */
1044 
1045 CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
sIsNullStream(const STREAM * stream)1046 BOOLEAN sIsNullStream( const STREAM *stream )
1047 	{
1048 	assert( isReadPtr( stream, sizeof( STREAM ) ) );
1049 
1050 	/* Check that the input parameters are in order */
1051 	if( !isReadPtrConst( stream, sizeof( STREAM ) ) )
1052 		retIntError_Boolean();
1053 
1054 	return( ( stream->type == STREAM_TYPE_NULL ) ? TRUE : FALSE );
1055 	}
1056 
1057 
1058 /* Move to an absolute position in a stream */
1059 
1060 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
sseek(INOUT STREAM * stream,IN_LENGTH_Z const long position)1061 int sseek( INOUT STREAM *stream, IN_LENGTH_Z const long position )
1062 	{
1063 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
1064 
1065 	/* Check that the input parameters are in order */
1066 	if( !isWritePtrConst( stream, sizeof( STREAM ) ) )
1067 		retIntError();
1068 
1069 	REQUIRES_S( sanityCheck( stream ) );
1070 	REQUIRES_S( stream->type == STREAM_TYPE_NULL || \
1071 				stream->type == STREAM_TYPE_MEMORY || \
1072 				stream->type == STREAM_TYPE_FILE );
1073 	REQUIRES_S( position >= 0 && position < MAX_BUFFER_SIZE );
1074 
1075 	/* If there's a problem with the stream don't try to do anything */
1076 	if( cryptStatusError( stream->status ) )
1077 		return( stream->status );
1078 
1079 	switch( stream->type )
1080 		{
1081 		case STREAM_TYPE_NULL:
1082 			/* Move to the position in the stream buffer.  We never get
1083 			   called directly with an sseek on a memory stream, but end up
1084 			   here via a translated sSkip() call */
1085 			stream->bufPos = ( int ) position;
1086 			if( stream->bufEnd < stream->bufPos )
1087 				stream->bufEnd = stream->bufPos;
1088 			break;
1089 
1090 		case STREAM_TYPE_MEMORY:
1091 			/* Move to the position in the stream buffer */
1092 			if( ( int ) position > stream->bufSize )
1093 				{
1094 				stream->bufPos = stream->bufSize;
1095 				return( sSetError( stream, CRYPT_ERROR_UNDERFLOW ) );
1096 				}
1097 			stream->bufPos = ( int ) position;
1098 			if( stream->bufEnd < stream->bufPos )
1099 				stream->bufEnd = stream->bufPos;
1100 			break;
1101 
1102 #ifdef USE_FILES
1103 		case STREAM_TYPE_FILE:
1104 			{
1105 			const int blockOffset = ( stream->bufSize > 0 ) ? \
1106 									position / stream->bufSize : 0;
1107 			const int byteOffset = ( stream->bufSize > 0 ) ? \
1108 								   position % stream->bufSize : 0;
1109 
1110 			/* If it's a currently-disconnected file stream then all we can
1111 			   do is rewind the stream.  This occurs when we're doing an
1112 			   atomic flush of data to disk and we rewind the stream prior
1113 			   to writing the new/updated data.  The next buffer-connect
1114 			   operation will reset the stream state so there's nothing to
1115 			   do at this point */
1116 			if( !( stream->flags & STREAM_FFLAG_BUFFERSET ) )
1117 				{
1118 				REQUIRES_S( position == 0 );
1119 
1120 				return( CRYPT_OK );
1121 				}
1122 
1123 			/* Determine which buffer-size block of data we're moving to */
1124 			if( ( stream->flags & STREAM_FFLAG_EOF ) && \
1125 				blockOffset > stream->bufCount )
1126 				{
1127 				/* If this is the last buffer's worth and we're trying to
1128 				   move past it, it's an error */
1129 				return( sSetError( stream, CRYPT_ERROR_UNDERFLOW ) );
1130 				}
1131 			if( blockOffset != stream->bufCount )
1132 				{
1133 				/* We're not within the current buffer any more, remember
1134 				   that we have to explicitly update the file position on
1135 				   the next read */
1136 				stream->flags |= STREAM_FFLAG_POSCHANGED;
1137 
1138 				/* If we're already positioned to read the next bufferful
1139 				   of data we don't have to explicitly skip ahead to it */
1140 				if( blockOffset == stream->bufCount + 1 )
1141 					stream->flags |= STREAM_FFLAG_POSCHANGED_NOSKIP;
1142 
1143 				stream->bufCount = blockOffset;
1144 				}
1145 
1146 			/* Now that we've got the buffer-sized block handled, set up
1147 			   the byte offset within the block */
1148 			if( ( stream->flags & STREAM_FFLAG_EOF ) && \
1149 				byteOffset > stream->bufEnd )
1150 				{
1151 				/* We've tried to move past EOF, this is an error */
1152 				return( sSetError( stream, CRYPT_ERROR_UNDERFLOW ) );
1153 				}
1154 
1155 			stream->bufPos = byteOffset;
1156 			break;
1157 			}
1158 #endif /* USE_FILES */
1159 
1160 		default:
1161 			retIntError_Stream( stream );
1162 		}
1163 
1164 	ENSURES_S( sanityCheck( stream ) );
1165 
1166 	return( CRYPT_OK );
1167 	}
1168 
1169 /* Return the current posision in a stream */
1170 
1171 CHECK_RETVAL_RANGE_NOERROR( 0, MAX_BUFFER_SIZE ) STDC_NONNULL_ARG( ( 1 ) ) \
stell(const STREAM * stream)1172 int stell( const STREAM *stream )
1173 	{
1174 	assert( isReadPtr( stream, sizeof( STREAM ) ) );
1175 
1176 	/* Check that the input parameters are in order */
1177 	if( !isReadPtrConst( stream, sizeof( STREAM ) ) )
1178 		retIntError();
1179 
1180 	/* We can't use REQUIRE_S( sanityCheck() ) in this case because the
1181 	   stream is a const parameter.  Since stell() is expected to return a
1182 	   value in the range 0...stream->bufSize we don't use REQUIRES() either
1183 	   but simply return an offset of zero */
1184 	REQUIRES_EXT( sanityCheck( stream ), 0 );
1185 	REQUIRES_EXT( ( stream->type == STREAM_TYPE_NULL || \
1186 					stream->type == STREAM_TYPE_MEMORY || \
1187 					stream->type == STREAM_TYPE_FILE ), 0 );
1188 
1189 	/* If there's a problem with the stream don't try to do anything */
1190 	if( cryptStatusError( stream->status ) )
1191 		{
1192 		DEBUG_DIAG(( "Stream is in invalid state" ));
1193 		assert( DEBUG_WARN );
1194 		return( 0 );
1195 		}
1196 
1197 	switch( stream->type )
1198 		{
1199 		case STREAM_TYPE_NULL:
1200 		case STREAM_TYPE_MEMORY:
1201 			return( stream->bufPos );
1202 
1203 #ifdef USE_FILES
1204 		case STREAM_TYPE_FILE:
1205 			return( ( stream->bufCount * stream->bufSize ) + \
1206 					stream->bufPos );
1207 #endif /* USE_FILES */
1208 		}
1209 
1210 	retIntError_Ext( 0 );
1211 	}
1212 
1213 /* Skip a number of bytes in a stream, with a bounds check on the maximum
1214    allowable offset to skip */
1215 
1216 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
sSkip(INOUT STREAM * stream,const long offset,IN_DATALENGTH const long maxOffset)1217 int sSkip( INOUT STREAM *stream, const long offset,
1218 		   IN_DATALENGTH const long maxOffset )
1219 	{
1220 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
1221 
1222 	/* Check that the input parameters are in order */
1223 	if( !isWritePtrConst( stream, sizeof( STREAM ) ) )
1224 		retIntError();
1225 
1226 	REQUIRES_S( sanityCheck( stream ) );
1227 	REQUIRES_S( stream->type == STREAM_TYPE_NULL || \
1228 				stream->type == STREAM_TYPE_MEMORY || \
1229 				stream->type == STREAM_TYPE_FILE );
1230 	REQUIRES_S( offset > 0 );
1231 	REQUIRES_S( maxOffset > 0 && maxOffset <= MAX_BUFFER_SIZE );
1232 
1233 	/* If there's a problem with the stream don't try to do anything */
1234 	if( cryptStatusError( stream->status ) )
1235 		return( stream->status );
1236 
1237 	/* Make sure that the offset to skip is valid */
1238 	if( offset > maxOffset || offset > MAX_BUFFER_SIZE - stream->bufPos )
1239 		return( CRYPT_ERROR_BADDATA );
1240 
1241 	return( sseek( stream, stream->bufPos + offset ) );
1242 	}
1243 
1244 /* Peek at the next data value in a stream */
1245 
1246 CHECK_RETVAL_RANGE( 0, 0xFF ) STDC_NONNULL_ARG( ( 1 ) ) \
sPeek(INOUT STREAM * stream)1247 int sPeek( INOUT STREAM *stream )
1248 	{
1249 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
1250 	assert( isReadPtr( stream->buffer, stream->bufSize ) );
1251 
1252 	/* Check that the input parameters are in order */
1253 	if( !isWritePtrConst( stream, sizeof( STREAM ) ) )
1254 		retIntError();
1255 
1256 	REQUIRES_S( sanityCheck( stream ) );
1257 	REQUIRES_S( stream->type == STREAM_TYPE_MEMORY || \
1258 				stream->type == STREAM_TYPE_FILE );
1259 
1260 	/* If there's a problem with the stream don't try to do anything until
1261 	   the error is cleared */
1262 	if( cryptStatusError( stream->status ) )
1263 		return( stream->status );
1264 
1265 	/* Read the data from the buffer, but without advancing the read pointer
1266 	   like sgetc() does */
1267 	switch( stream->type )
1268 		{
1269 		case STREAM_TYPE_MEMORY:
1270 			/* Read the data from the stream buffer */
1271 			if( stream->bufPos >= stream->bufEnd )
1272 				return( sSetError( stream, CRYPT_ERROR_UNDERFLOW ) );
1273 			return( stream->buffer[ stream->bufPos ] );
1274 
1275 #ifdef USE_FILES
1276 		case STREAM_TYPE_FILE:
1277 			REQUIRES_S( stream->flags & STREAM_FFLAG_BUFFERSET );
1278 
1279 			/* Read the data from the file */
1280 			if( stream->bufPos >= stream->bufEnd || \
1281 				( stream->flags & STREAM_FFLAG_POSCHANGED ) )
1282 				{
1283 				int status = refillStream( stream );
1284 				if( cryptStatusError( status ) )
1285 					return( ( status == OK_SPECIAL ) ? 0 : status );
1286 				}
1287 			return( stream->buffer[ stream->bufPos ] );
1288 #endif /* USE_FILES */
1289 		}
1290 
1291 	retIntError_Stream( stream );
1292 	}
1293 
1294 /****************************************************************************
1295 *																			*
1296 *								IOCTL Functions								*
1297 *																			*
1298 ****************************************************************************/
1299 
1300 /* Perform an IOCTL on a stream.  There are two variations of this, a get and
1301    a set form, which helps with type-checking compared to the usual do-anything
1302    ioctl() */
1303 
1304 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
setStreamBuffer(INOUT STREAM * stream,IN_BUFFER_OPT (dataLen)const void * data,IN_DATALENGTH_Z const int dataLen)1305 static int setStreamBuffer( INOUT STREAM *stream,
1306 							IN_BUFFER_OPT( dataLen ) const void *data,
1307 							IN_DATALENGTH_Z const int dataLen )
1308 	{
1309 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
1310 	assert( ( data == NULL && dataLen == 0 ) || \
1311 			isReadPtr( data, dataLen ) );
1312 
1313 	REQUIRES_S( ( data == NULL && dataLen == 0 ) || \
1314 				( data != NULL && \
1315 				  dataLen > 0 && dataLen < MAX_BUFFER_SIZE ) );
1316 	REQUIRES_S( dataLen == 0 || \
1317 				dataLen == 512 || dataLen == 1024 || \
1318 				dataLen == 2048 || dataLen == 4096 || \
1319 				dataLen == 8192 || dataLen == 16384 );
1320 
1321 #ifdef VIRTUAL_FILE_STREAM
1322 	/* If it's a virtual file stream emulated in memory, don't do anything */
1323 	if( sIsVirtualFileStream( stream ) )
1324 		return( CRYPT_OK );
1325 #endif /* VIRTUAL_FILE_STREAM */
1326 
1327 	/* Set up the buffer variables.  File streams don't make use of the
1328 	   bufEnd indicator so we set it to the same value as bufSize to ensure
1329 	   that the stream passes the sanity checks */
1330 	stream->buffer = ( void * ) data;
1331 	stream->bufSize = stream->bufEnd = dataLen;
1332 
1333 	/* We've switched to a new I/O buffer, reset all buffer- and stream-
1334 	   state related variables and remember that we have to reset the stream
1335 	   position since there may be a position-change pending that hasn't
1336 	   been reflected down to the underlying file yet (if the position
1337 	   change was within the same buffer then the POSCHANGED flag won't have
1338 	   been set since only the bufPos will have changed) */
1339 	stream->bufPos = stream->bufCount = 0;
1340 	sClearError( stream );
1341 	stream->flags &= ~( STREAM_FFLAG_BUFFERSET | \
1342 						STREAM_FFLAG_EOF | \
1343 						STREAM_FFLAG_POSCHANGED_NOSKIP );
1344 	stream->flags |= STREAM_FFLAG_POSCHANGED;
1345 	if( data != NULL )
1346 		stream->flags |= STREAM_FFLAG_BUFFERSET;
1347 
1348 	return( CRYPT_OK );
1349 	}
1350 
1351 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
sioctlSet(INOUT STREAM * stream,IN_ENUM (STREAM_IOCTL)const STREAM_IOCTL_TYPE type,const int value)1352 int sioctlSet( INOUT STREAM *stream,
1353 			   IN_ENUM( STREAM_IOCTL ) const STREAM_IOCTL_TYPE type,
1354 			   const int value )
1355 	{
1356 #ifdef USE_TCP
1357 	NET_STREAM_INFO *netStream = ( NET_STREAM_INFO * ) stream->netStreamInfo;
1358 	int status;
1359 #endif /* USE_TCP */
1360 
1361 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
1362 
1363 	/* Check that the input parameters are in order */
1364 	if( !isWritePtrConst( stream, sizeof( STREAM ) ) )
1365 		retIntError();
1366 
1367 	/* If this is a pseudo-stream then there's no network information
1368 	   present to set information for */
1369 #ifndef NDEBUG
1370 	if( sIsPseudoStream( stream ) )
1371 		return( CRYPT_OK );
1372 #endif /* !NDEBUG */
1373 
1374 	REQUIRES_S( sanityCheck( stream ) );
1375 	REQUIRES_S( ( ( stream->type == STREAM_TYPE_FILE || \
1376 					sIsVirtualFileStream( stream ) ) && \
1377 				( type == STREAM_IOCTL_IOBUFFER || \
1378 				  type == STREAM_IOCTL_PARTIALREAD ) ) || \
1379 				( stream->type == STREAM_TYPE_NETWORK ) );
1380 	REQUIRES_S( type > STREAM_IOCTL_NONE && type < STREAM_IOCTL_LAST );
1381 	REQUIRES_S( value >= 0 && value < MAX_INTLENGTH );
1382 
1383 	switch( type )
1384 		{
1385 		case STREAM_IOCTL_IOBUFFER:
1386 			REQUIRES_S( value == 0 );
1387 
1388 			return( setStreamBuffer( stream, NULL, 0 ) );
1389 
1390 		case STREAM_IOCTL_PARTIALREAD:
1391 			REQUIRES_S( value == FALSE || value == TRUE );
1392 
1393 			if( value )
1394 				stream->flags |= STREAM_FLAG_PARTIALREAD;
1395 			else
1396 				stream->flags &= ~STREAM_FLAG_PARTIALREAD;
1397 
1398 			return( CRYPT_OK );
1399 
1400 		case STREAM_IOCTL_PARTIALWRITE:
1401 			REQUIRES_S( value == FALSE || value == TRUE );
1402 
1403 			if( value )
1404 				stream->flags |= STREAM_FLAG_PARTIALWRITE;
1405 			else
1406 				stream->flags &= ~STREAM_FLAG_PARTIALWRITE;
1407 
1408 			return( CRYPT_OK );
1409 
1410 #ifdef USE_TCP
1411 		case STREAM_IOCTL_READTIMEOUT:
1412 		case STREAM_IOCTL_WRITETIMEOUT:
1413 			REQUIRES_S( value >= 0 && value < MAX_INTLENGTH );
1414 
1415 			netStream->timeout = value;
1416 			if( netStream->iTransportSession != CRYPT_ERROR )
1417 				{
1418 				status = krnlSendMessage( netStream->iTransportSession,
1419 								IMESSAGE_SETATTRIBUTE, &netStream->timeout,
1420 								( type == STREAM_IOCTL_READTIMEOUT ) ? \
1421 									CRYPT_OPTION_NET_READTIMEOUT : \
1422 									CRYPT_OPTION_NET_WRITETIMEOUT );
1423 				if( cryptStatusError( status ) )
1424 					return( status );
1425 				}
1426 			return( CRYPT_OK );
1427 
1428 		case STREAM_IOCTL_HANDSHAKECOMPLETE:
1429 			REQUIRES_S( value == TRUE );
1430 			REQUIRES_S( netStream->timeout > 0 && \
1431 						netStream->timeout < MAX_INTLENGTH );
1432 			REQUIRES_S( netStream->savedTimeout >= 0 && \
1433 						netStream->savedTimeout < MAX_INTLENGTH );
1434 
1435 			/* The security protocol handshake has completed, change the
1436 			   stream timeout value from the connect/handshake timeout to
1437 			   the standard data transfer timeout */
1438 			netStream->timeout = netStream->savedTimeout;
1439 			netStream->savedTimeout = CRYPT_ERROR;
1440 			if( netStream->iTransportSession != CRYPT_ERROR )
1441 				{
1442 				status = krnlSendMessage( netStream->iTransportSession,
1443 									IMESSAGE_SETATTRIBUTE, &netStream->timeout,
1444 									CRYPT_OPTION_NET_CONNECTTIMEOUT );
1445 				if( cryptStatusError( status ) )
1446 					return( status );
1447 				}
1448 			return( CRYPT_OK );
1449 
1450 		case STREAM_IOCTL_LASTMESSAGE:
1451 			REQUIRES_S( value == TRUE );
1452 			REQUIRES_S( netStream->protocol == STREAM_PROTOCOL_HTTP );
1453 
1454 			netStream->nFlags |= STREAM_NFLAG_LASTMSGW;
1455 			return( CRYPT_OK );
1456 
1457 		case STREAM_IOCTL_HTTPREQTYPES:
1458 			REQUIRES_S( value > STREAM_HTTPREQTYPE_NONE && \
1459 						value < STREAM_HTTPREQTYPE_LAST );
1460 			REQUIRES_S( netStream->protocol == STREAM_PROTOCOL_HTTP );
1461 
1462 			netStream->nFlags &= ~STREAM_NFLAG_HTTPREQMASK;
1463 			switch( value )
1464 				{
1465 				case STREAM_HTTPREQTYPE_GET:
1466 					netStream->nFlags |= STREAM_NFLAG_HTTPGET;
1467 					break;
1468 
1469 				case STREAM_HTTPREQTYPE_POST:
1470 					netStream->nFlags |= STREAM_NFLAG_HTTPPOST;
1471 					break;
1472 
1473 				case STREAM_HTTPREQTYPE_POST_AS_GET:
1474 					/* This flag modifies the HTTP POST to encode it as a
1475 					   GET, for b0rken servers that don't support POST */
1476 					netStream->nFlags |= STREAM_NFLAG_HTTPPOST | \
1477 										 STREAM_NFLAG_HTTPPOST_AS_GET;
1478 					break;
1479 
1480 				case STREAM_HTTPREQTYPE_ANY:
1481 					netStream->nFlags |= STREAM_NFLAG_HTTPGET | \
1482 										 STREAM_NFLAG_HTTPPOST;
1483 					break;
1484 
1485 				default:
1486 					retIntError();
1487 				}
1488 
1489 			/* If only an HTTP GET is possible and it's a client-side
1490 			   stream, it's read-only */
1491 			if( value == STREAM_HTTPREQTYPE_GET && \
1492 				!( netStream->nFlags & STREAM_NFLAG_ISSERVER ) )
1493 				stream->flags = STREAM_FLAG_READONLY;
1494 			else
1495 				{
1496 				/* Reset the read-only flag if we're changing the HTTP
1497 				   operation type to one that allows writes */
1498 				stream->flags &= ~STREAM_FLAG_READONLY;
1499 				}
1500 			return( CRYPT_OK );
1501 
1502 		case STREAM_IOCTL_CLOSESENDCHANNEL:
1503 			{
1504 			const STM_TRANSPORTDISCONNECT_FUNCTION transportDisconnectFunction = \
1505 							FNPTR_GET( netStream->transportDisconnectFunction );
1506 
1507 			REQUIRES_S( value == TRUE );
1508 			REQUIRES_S( !( netStream->nFlags & STREAM_NFLAG_USERSOCKET ) );
1509 			REQUIRES_S( transportDisconnectFunction != NULL );
1510 
1511 			/* If this is a user-supplied socket we can't perform a partial
1512 			   close without affecting the socket as seen by the user so we
1513 			   only perform the partial close if it's a cryptlib-controlled
1514 			   socket */
1515 			if( !( netStream->nFlags & STREAM_NFLAG_USERSOCKET ) )
1516 				transportDisconnectFunction( netStream, FALSE );
1517 
1518 			return( CRYPT_OK );
1519 			}
1520 #endif /* USE_TCP */
1521 		}
1522 
1523 	retIntError_Stream( stream );
1524 	}
1525 
1526 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
sioctlSetString(INOUT STREAM * stream,IN_ENUM (STREAM_IOCTL)const STREAM_IOCTL_TYPE type,IN_BUFFER (dataLen)const void * data,IN_DATALENGTH const int dataLen)1527 int sioctlSetString( INOUT STREAM *stream,
1528 					 IN_ENUM( STREAM_IOCTL ) const STREAM_IOCTL_TYPE type,
1529 					 IN_BUFFER( dataLen ) const void *data,
1530 					 IN_DATALENGTH const int dataLen )
1531 	{
1532 #ifdef USE_TCP
1533 	NET_STREAM_INFO *netStream = ( NET_STREAM_INFO * ) stream->netStreamInfo;
1534 #endif /* USE_TCP */
1535 
1536 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
1537 	assert( isReadPtr( data, dataLen ) );
1538 
1539 	/* Check that the input parameters are in order */
1540 	if( !isWritePtrConst( stream, sizeof( STREAM ) ) )
1541 		retIntError();
1542 
1543 	REQUIRES_S( sanityCheck( stream ) );
1544 #ifndef NDEBUG
1545 	REQUIRES_S( ( sIsPseudoStream( stream ) && \
1546 				  type == STREAM_IOCTL_ERRORINFO ) || \
1547 				( ( stream->type == STREAM_TYPE_FILE || \
1548 					sIsVirtualFileStream( stream ) ) && \
1549 				  ( type == STREAM_IOCTL_ERRORINFO || \
1550 					type == STREAM_IOCTL_IOBUFFER ) ) || \
1551 				( stream->type == STREAM_TYPE_NETWORK ) );
1552 #else
1553 	REQUIRES_S( ( ( stream->type == STREAM_TYPE_FILE || \
1554 					sIsVirtualFileStream( stream ) ) && \
1555 				  ( type == STREAM_IOCTL_ERRORINFO || \
1556 					type == STREAM_IOCTL_IOBUFFER ) ) || \
1557 				( stream->type == STREAM_TYPE_NETWORK ) );
1558 #endif /* !NDEBUG */
1559 	REQUIRES_S( type > STREAM_IOCTL_NONE && type < STREAM_IOCTL_LAST );
1560 	REQUIRES_S( dataLen > 0 && dataLen < MAX_BUFFER_SIZE );
1561 
1562 	switch( type )
1563 		{
1564 		case STREAM_IOCTL_ERRORINFO:
1565 			REQUIRES_S( dataLen == sizeof( ERROR_INFO ) );
1566 
1567 			/* If this stream type doesn't record extended error information,
1568 			   there's nothing to do */
1569 			if( stream->type != STREAM_TYPE_NETWORK )
1570 				return( CRYPT_OK );
1571 
1572 #ifdef USE_TCP
1573 			/* Copy the error information to the stream */
1574 			copyErrorInfo( NETSTREAM_ERRINFO, data );
1575 #endif /* USE_TCP */
1576 			return( CRYPT_OK );
1577 
1578 		case STREAM_IOCTL_IOBUFFER:
1579 			REQUIRES_S( dataLen == 0 || \
1580 						dataLen == 512 || dataLen == 1024 || \
1581 						dataLen == 2048 || dataLen == 4096 || \
1582 						dataLen == 8192 || dataLen == 16384 );
1583 
1584 			return( setStreamBuffer( stream, data, dataLen ) );
1585 		}
1586 
1587 	retIntError_Stream( stream );
1588 	}
1589 
1590 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
sioctlGet(INOUT STREAM * stream,IN_ENUM (STREAM_IOCTL)const STREAM_IOCTL_TYPE type,OUT_BUFFER_FIXED (dataMaxLen)void * data,IN_LENGTH_SHORT const int dataMaxLen)1591 int sioctlGet( INOUT STREAM *stream,
1592 			   IN_ENUM( STREAM_IOCTL ) const STREAM_IOCTL_TYPE type,
1593 			   OUT_BUFFER_FIXED( dataMaxLen ) void *data,
1594 			   IN_LENGTH_SHORT const int dataMaxLen )
1595 	{
1596 #ifdef USE_TCP
1597 	NET_STREAM_INFO *netStream = ( NET_STREAM_INFO * ) stream->netStreamInfo;
1598 #endif /* USE_TCP */
1599 
1600 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
1601 	assert( isWritePtr( data, dataMaxLen ) );
1602 
1603 	/* Check that the input parameters are in order */
1604 	if( !isWritePtrConst( stream, sizeof( STREAM ) ) )
1605 		retIntError();
1606 
1607 	/* If this is a pseudo-stream then there's no network information
1608 	   present to get error information from */
1609 #ifndef NDEBUG
1610 	if( sIsPseudoStream( stream ) )
1611 		{
1612 		memset( data, 0, dataMaxLen );
1613 		return( CRYPT_OK );
1614 		}
1615 #endif /* !NDEBUG */
1616 
1617 	REQUIRES_S( sanityCheck( stream ) );
1618 	REQUIRES_S( stream->type == STREAM_TYPE_NETWORK );
1619 	REQUIRES_S( type > STREAM_IOCTL_NONE && type < STREAM_IOCTL_LAST );
1620 	REQUIRES_S( data != NULL );
1621 	REQUIRES_S( dataMaxLen > 0 && dataMaxLen < MAX_INTLENGTH_SHORT );
1622 
1623 	switch( type )
1624 		{
1625 #ifdef USE_TCP
1626 		case STREAM_IOCTL_READTIMEOUT:
1627 		case STREAM_IOCTL_WRITETIMEOUT:
1628 			REQUIRES_S( dataMaxLen == sizeof( int ) );
1629 
1630 			/* These two values are stored as a shared timeout value
1631 			   which is updated on each data read or write by the
1632 			   caller so there's no need to maintain distinct values */
1633 			*( ( int * ) data ) = netStream->timeout;
1634 			return( CRYPT_OK );
1635 
1636 		case STREAM_IOCTL_CONNSTATE:
1637 			REQUIRES_S( dataMaxLen == sizeof( int ) );
1638 
1639 			*( ( int * ) data ) = \
1640 				( netStream->nFlags & STREAM_NFLAG_LASTMSGR ) ? FALSE : TRUE;
1641 			return( CRYPT_OK );
1642 
1643 		case STREAM_IOCTL_GETCLIENTNAME:
1644 			REQUIRES_S( dataMaxLen > 8 && dataMaxLen < MAX_INTLENGTH_SHORT );
1645 
1646 			if( netStream->clientAddressLen <= 0 )
1647 				return( CRYPT_ERROR_NOTFOUND );
1648 			if( netStream->clientAddressLen > dataMaxLen )
1649 				return( CRYPT_ERROR_OVERFLOW );
1650 			memcpy( data, netStream->clientAddress, netStream->clientAddressLen );
1651 
1652 			return( CRYPT_OK );
1653 
1654 		case STREAM_IOCTL_GETCLIENTNAMELEN:
1655 			REQUIRES_S( dataMaxLen == sizeof( int ) );
1656 
1657 			if( netStream->clientAddressLen <= 0 )
1658 				return( CRYPT_ERROR_NOTFOUND );
1659 			*( ( int * ) data ) = netStream->clientAddressLen;
1660 
1661 			return( CRYPT_OK );
1662 
1663 		case STREAM_IOCTL_GETPEERTYPE:
1664 			REQUIRES_S( dataMaxLen == sizeof( STREAM_PEER_TYPE ) );
1665 
1666 			*( ( STREAM_PEER_TYPE * ) data ) = netStream->systemType;
1667 
1668 			return( CRYPT_OK );
1669 
1670 		case STREAM_IOCTL_GETCLIENTPORT:
1671 			REQUIRES_S( dataMaxLen == sizeof( int ) );
1672 
1673 			if( netStream->clientPort <= 0 )
1674 				return( CRYPT_ERROR_NOTFOUND );
1675 			*( ( int * ) data ) = netStream->clientPort;
1676 
1677 			return( CRYPT_OK );
1678 
1679 #endif /* USE_TCP */
1680 		}
1681 
1682 	retIntError_Stream( stream );
1683 	}
1684 
1685 /****************************************************************************
1686 *																			*
1687 *								Misc Functions								*
1688 *																			*
1689 ****************************************************************************/
1690 
1691 #ifdef USE_FILES
1692 
1693 /* Convert a file stream to a memory stream.  Usually this allocates a
1694    buffer and reads the stream into it, however if it's a read-only memory-
1695    mapped file it just creates a second reference to the data to save
1696    memory */
1697 
1698 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
sFileToMemStream(OUT STREAM * memStream,INOUT STREAM * fileStream,OUT_BUFFER_ALLOC_OPT (length)void ** bufPtrPtr,IN_DATALENGTH const int length)1699 int sFileToMemStream( OUT STREAM *memStream,
1700 					  INOUT STREAM *fileStream,
1701 					  OUT_BUFFER_ALLOC_OPT( length ) void **bufPtrPtr,
1702 					  IN_DATALENGTH const int length )
1703 	{
1704 	void *bufPtr;
1705 	int status;
1706 
1707 	assert( isWritePtr( memStream, sizeof( STREAM ) ) );
1708 	assert( isWritePtr( fileStream, sizeof( STREAM ) ) );
1709 	assert( isWritePtr( bufPtrPtr, sizeof( void * ) ) );
1710 
1711 	/* Check that the input parameters are in order */
1712 	if( !isWritePtrConst( memStream, sizeof( STREAM ) ) || \
1713 		!isWritePtrConst( fileStream, sizeof( STREAM ) ) || \
1714 		!isWritePtrConst( bufPtrPtr, sizeof( void * ) ) )
1715 		{
1716 		/* Since memStream() is an OUT parameter we can't use it with a
1717 		   retIntError_Stream() but have to use a plain retIntError() */
1718 		retIntError();
1719 		}
1720 
1721 	/* We have to use REQUIRES() here rather than REQUIRES_S() since it's
1722 	   not certain which of the two streams to set the status for */
1723 	REQUIRES( sanityCheck( fileStream ) && \
1724 			  fileStream->flags & STREAM_FFLAG_BUFFERSET );
1725 	REQUIRES( fileStream->type == STREAM_TYPE_FILE );
1726 	REQUIRES( length > 0 && length < MAX_BUFFER_SIZE );
1727 
1728 	/* Clear return value */
1729 	memset( memStream, 0, sizeof( STREAM ) );
1730 	*bufPtrPtr = NULL;
1731 
1732 #ifdef VIRTUAL_FILE_STREAM
1733 	/* If it's a read-only memory-mapped file stream create the memory
1734 	   stream as a reference to the file stream */
1735 	if( ( fileStream->flags & \
1736 		  ( STREAM_FLAG_READONLY | STREAM_FFLAG_MMAPPED ) ) == \
1737 		( STREAM_FLAG_READONLY | STREAM_FFLAG_MMAPPED ) )
1738 		{
1739 		/* Make sure that there's enough data left in the memory-mapped
1740 		   stream to reference it as a file stream */
1741 		if( length > fileStream->bufSize - fileStream->bufPos )
1742 			return( CRYPT_ERROR_UNDERFLOW );
1743 
1744 		/* Create a second reference to the memory-mapped stream and advance
1745 		   the read pointer in the memory-mapped file stream to mimic the
1746 		   behaviour of a read from it to the memory stream */
1747 		sMemConnect( memStream, fileStream->buffer + fileStream->bufPos,
1748 					length );
1749 		status = sSkip( fileStream, length, SSKIP_MAX );
1750 		if( cryptStatusError( status ) )
1751 			{
1752 			sMemDisconnect( memStream );
1753 			return( status );
1754 			}
1755 		return( CRYPT_OK );
1756 		}
1757 #endif /* VIRTUAL_FILE_STREAM */
1758 
1759 	/* It's a file stream, allocate a buffer for the data and read it in as
1760 	   a memory stream */
1761 	if( ( bufPtr = clAlloc( "sFileToMemStream", length ) ) == NULL )
1762 		return( CRYPT_ERROR_MEMORY );
1763 	status = sread( fileStream, bufPtr, length );
1764 	if( cryptStatusError( status ) )
1765 		{
1766 		clFree( "sFileToMemStream", bufPtr );
1767 		return( status );
1768 		}
1769 	sMemConnect( memStream, bufPtr, length );
1770 	*bufPtrPtr = bufPtr;
1771 	return( CRYPT_OK );
1772 	}
1773 #endif /* USE_FILES */
1774