1 /****************************************************************************
2 *																			*
3 *						  Memory Stream I/O Functions						*
4 *						Copyright Peter Gutmann 1993-2008					*
5 *																			*
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9   #include "stream_int.h"
10 #else
11   #include "io/stream_int.h"
12 #endif /* Compiler-specific includes */
13 
14 /****************************************************************************
15 *																			*
16 *								Utility Functions							*
17 *																			*
18 ****************************************************************************/
19 
20 /* Sanity-check the stream state */
21 
22 CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
sanityCheck(const STREAM * stream)23 static BOOLEAN sanityCheck( const STREAM *stream )
24 	{
25 	assert( isReadPtr( stream, sizeof( STREAM ) ) );
26 
27 	/* Null streams have no internal buffer so the buffer position
28 	   indicators aren't used */
29 	if( stream->type == STREAM_TYPE_NULL )
30 		{
31 		/* Null streams, which act as data sinks, have a content-size
32 		   indicator so although the buffer size is zero the buffer
33 		   position values can be nonzero */
34 		if( stream->bufSize != 0 )
35 			return( FALSE );
36 		if( stream->bufPos < 0 || stream->bufPos > stream->bufEnd ||
37 			stream->bufEnd < 0 || stream->bufEnd >= MAX_BUFFER_SIZE )
38 			return( FALSE );
39 
40 		return( TRUE );
41 		}
42 
43 	/* If it's not a null stream it has to be a memory stream */
44 	if( stream->type != STREAM_TYPE_MEMORY )
45 		return( FALSE );
46 
47 	/* Make sure that the buffer position is within bounds:
48 
49 								 bufEnd
50 									|
51 			<------ buffer ------>	v
52 		+---------------------------+
53 		|						|	|
54 		+---------------------------+
55 				^				^
56 				|				|
57 			 bufPos			 bufEnd */
58 	if( stream->bufPos < 0 || stream->bufPos > stream->bufEnd || \
59 		stream->bufEnd < 0 || stream->bufEnd > stream->bufSize || \
60 		stream->bufSize <= 0 || stream->bufSize >= MAX_BUFFER_SIZE )
61 		return( FALSE );
62 
63 	return( TRUE );
64 	}
65 
66 /****************************************************************************
67 *																			*
68 *								Open/Close Functions						*
69 *																			*
70 ****************************************************************************/
71 
72 /* Initialise and shut down a memory stream.  Since the return value for the
73    memory stream open functions is rarely (if ever) checked we validate the
74    buffer and length parameters later and create a read-only null stream if
75    they're invalid, so that reads and writes return error conditions if
76    they're attempted.  For the same reason we just use a basic assert()
77    rather than the stronger REQUIRES() so that we can explicitly handle any
78    parameter errors later in the code */
79 
80 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
initMemoryStream(OUT STREAM * stream,const BOOLEAN isNullStream)81 static int initMemoryStream( OUT STREAM *stream,
82 							 const BOOLEAN isNullStream )
83 	{
84 	/* We don't use a REQUIRES() predicate here for the reasons given in the
85 	   comments above */
86 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
87 
88 	/* Check that the input parameters are in order */
89 	if( !isWritePtrConst( stream, sizeof( STREAM ) ) )
90 		retIntError();
91 
92 	/* Clear the stream data and initialise the stream structure.  Further
93 	   initialisation of stream buffer parameters will be done by the
94 	   caller */
95 	memset( stream, 0, sizeof( STREAM ) );
96 	stream->type = ( isNullStream ) ? STREAM_TYPE_NULL : STREAM_TYPE_MEMORY;
97 
98 	return( CRYPT_OK );
99 	}
100 
101 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
checkMemoryStreamParams(INOUT STREAM * stream,IN const void * buffer,IN_LENGTH_Z const int length)102 static int checkMemoryStreamParams( INOUT STREAM *stream,
103 									IN const void *buffer,
104 										/* May be unintialised for sMemOpen()
105 										   so we can't use IN_BUFFER */
106 									IN_LENGTH_Z const int length )
107 	{
108 	/* We don't use a REQUIRES() predicate here for the reasons given in the
109 	   comments above */
110 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
111 	assert( length > 0 && length < MAX_BUFFER_SIZE );
112 	assert( isReadPtr( buffer, length ) );
113 
114 	/* If there's a problem with the parameters, return an error code but
115 	   also make it a (non-readable, non-writeable) null stream with the
116 	   error state set via retIntError_Stream() so that it can be safely
117 	   used */
118 	if( length < 1 || length >= MAX_BUFFER_SIZE || \
119 		!isReadPtr( buffer, length ) )
120 		{
121 		stream->type = STREAM_TYPE_NULL;
122 		stream->flags = STREAM_FLAG_READONLY;
123 		retIntError_Stream( stream );
124 		}
125 
126 	return( CRYPT_OK );
127 	}
128 
129 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
shutdownMemoryStream(INOUT STREAM * stream,const BOOLEAN clearStreamBuffer)130 static int shutdownMemoryStream( INOUT STREAM *stream,
131 								 const BOOLEAN clearStreamBuffer )
132 	{
133 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
134 
135 	/* Check that the input parameters are in order */
136 	if( !isWritePtrConst( stream, sizeof( STREAM ) ) )
137 		retIntError();
138 
139 	REQUIRES( stream->type == STREAM_TYPE_NULL || \
140 			  stream->type == STREAM_TYPE_MEMORY );
141 
142 	/* Clear the stream structure */
143 	if( clearStreamBuffer && stream->buffer != NULL && stream->bufEnd > 0 )
144 		zeroise( stream->buffer, stream->bufEnd );
145 	zeroise( stream, sizeof( STREAM ) );
146 
147 	return( CRYPT_OK );
148 	}
149 
150 /* Open/close a memory stream or a null stream that serves as a data sink,
151    which is useful for implementing sizeof() functions by writing data to
152    null streams.  If calling sMemOpenOpt() and the buffer parameter is NULL
153    and the length is zero this creates a null stream, otherwise is creates
154    a standard memory stream.  This is useful for functions that follow the
155    convention of being passed a null buffer for a length check and a non-
156    null buffer to produce output.
157 
158    We don't use REQUIRES() predicates for these functions for the reasons
159    given in the comments in initMemoryStream().
160 
161    Note that the open/connect functions are declared with a void return
162    type, this is because they're used in hundreds of locations and the only
163    situation in which they can fail is a programming error.  Because of
164    this, problems are caught by throwing exceptions in debug builds rather
165    than having to add error handling for every case where they're used.  In
166    addition the functions always initialise the stream, setting it to an
167    invalid stream if there's an error, so there's no real need to check a
168    return value */
169 
170 STDC_NONNULL_ARG( ( 1, 2 ) ) \
sMemOpen(OUT STREAM * stream,OUT_BUFFER_FIXED (length)void * buffer,IN_LENGTH const int length)171 void sMemOpen( OUT STREAM *stream,
172 			   OUT_BUFFER_FIXED( length ) void *buffer,
173 			   IN_LENGTH const int length )
174 	{
175 	int status;
176 
177 	/* REQUIRES() checking done in initMemoryStream() */
178 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
179 	assert( isWritePtr( buffer, length ) );
180 	assert( length > 0 && length < MAX_BUFFER_SIZE );
181 
182 	/* Initialise the memory stream */
183 	status = initMemoryStream( stream, FALSE );
184 	ENSURES_V( cryptStatusOK( status ) );
185 	status = checkMemoryStreamParams( stream, buffer, length );
186 	ENSURES_V( cryptStatusOK( status ) );
187 	stream->buffer = buffer;
188 	stream->bufSize = length;
189 
190 	/* Clear the stream buffer.  Since this can be arbitrarily large we only
191 	   clear the entire buffer in the debug version */
192 #ifdef NDEBUG
193 	memset( stream->buffer, 0, min( 16, stream->bufSize ) );
194 #else
195 	memset( stream->buffer, 0, stream->bufSize );
196 #endif /* NDEBUG */
197 	}
198 
199 STDC_NONNULL_ARG( ( 1 ) ) \
sMemNullOpen(OUT STREAM * stream)200 void sMemNullOpen( OUT STREAM *stream )
201 	{
202 	int status;
203 
204 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
205 
206 	/* Initialise the memory stream */
207 	status = initMemoryStream( stream, TRUE );
208 	ENSURES_V( cryptStatusOK( status ) );
209 	}
210 
211 STDC_NONNULL_ARG( ( 1 ) ) \
sMemOpenOpt(OUT STREAM * stream,OUT_BUFFER_OPT_FIXED (length)void * buffer,IN_LENGTH_Z const int length)212 void sMemOpenOpt( OUT STREAM *stream,
213 				  OUT_BUFFER_OPT_FIXED( length ) void *buffer,
214 				  IN_LENGTH_Z const int length )
215 	{
216 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
217 	assert( ( buffer == NULL && length == 0 ) || \
218 			isReadPtr( buffer, length ) );
219 
220 	/* Note that the following must be given as 'buffer == NULL' without an
221 	   additional 'length == 0' because static-analysis tools can't make the
222 	   connection between 'buffer' and 'length' and will warn that the value
223 	   passed to sMemOpen() may be NULL */
224 	if( buffer == NULL )
225 		{
226 		sMemNullOpen( stream );
227 		return;
228 		}
229 	sMemOpen( stream, buffer, length );
230 	}
231 
232 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
sMemClose(INOUT STREAM * stream)233 int sMemClose( INOUT STREAM *stream )
234 	{
235 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
236 
237 	REQUIRES( sanityCheck( stream ) );
238 	REQUIRES( !( stream->flags & STREAM_FLAG_READONLY ) );
239 #ifdef CONFIG_FUZZ
240 	REQUIRES( !( stream->flags & STREAM_MFLAG_PSEUDO ) );
241 #endif /* CONFIG_FUZZ */
242 
243 	return( shutdownMemoryStream( stream, TRUE ) );
244 	}
245 
246 /* Connect/disconnect a memory stream without destroying the buffer
247    contents */
248 
249 STDC_NONNULL_ARG( ( 1, 2 ) ) \
sMemConnect(OUT STREAM * stream,IN_BUFFER (length)const void * buffer,IN_LENGTH const int length)250 void sMemConnect( OUT STREAM *stream,
251 				  IN_BUFFER( length ) const void *buffer,
252 				  IN_LENGTH const int length )
253 	{
254 	int status;
255 
256 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
257 	assert( length > 0 && length < MAX_BUFFER_SIZE );
258 	assert( isReadPtr( buffer, length ) );
259 
260 	/* Initialise the memory stream.  We don't use a REQUIRES() predicate
261 	   for the reasons given in the comments in initMemoryStream() */
262 	status = initMemoryStream( stream, FALSE );
263 	ENSURES_V( cryptStatusOK( status ) );
264 	status = checkMemoryStreamParams( stream, buffer, length );
265 	ENSURES_V( cryptStatusOK( status ) );
266 	stream->buffer = ( void * ) buffer;
267 	stream->bufSize = length;
268 
269 	/* Initialise further portions of the stream structure.  This is a read-
270 	   only stream so what's in the buffer at the start is all we'll ever
271 	   get */
272 	stream->bufEnd = length;
273 	stream->flags = STREAM_FLAG_READONLY;
274 	}
275 
276 #ifndef NDEBUG
277 
278 STDC_NONNULL_ARG( ( 1, 2 ) ) \
sMemPseudoConnect(OUT STREAM * stream,IN_BUFFER (length)const void * buffer,IN_LENGTH const int length)279 void sMemPseudoConnect( OUT STREAM *stream,
280 					    IN_BUFFER( length ) const void *buffer,
281 					    IN_LENGTH const int length )
282 	{
283 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
284 	assert( length > 0 && length < MAX_BUFFER_SIZE );
285 	assert( isReadPtr( buffer, length ) );
286 
287 	/* Open the stream as a standard memory stream */
288 	sMemConnect( stream, buffer, length );
289 
290 	/* We've now got a standard memory stream, modify it to make it pseudo-
291 	   writeable, in the sense that written data is discarded (this also
292 	   removes the read-only flag from the standard memory stream) */
293 	stream->flags = STREAM_MFLAG_PSEUDO;
294 	}
295 #endif /* !NDEBUG */
296 
297 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
sMemDisconnect(INOUT STREAM * stream)298 int sMemDisconnect( INOUT STREAM *stream )
299 	{
300 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
301 
302 	REQUIRES( sanityCheck( stream ) );
303 
304 	return( shutdownMemoryStream( stream, FALSE ) );
305 	}
306 
307 /****************************************************************************
308 *																			*
309 *							Direct Access Functions							*
310 *																			*
311 ****************************************************************************/
312 
313 /* Memory stream direct-access functions, used when the contents of a memory
314    stream need to be encrypted/decrypted/signed/MACd.  The basic
315    sMemGetDataBlock() returns a data block of a given size from the current
316    stream position, sMemGetDataBlockAbs() returns a data block from the
317    given stream position, and sMemGetDataBlockRemaining() returns a data
318    block containing all remaining data available in the stream */
319 
320 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
getMemoryBlock(INOUT STREAM * stream,OUT_BUFFER_ALLOC_OPT (length)void ** dataPtrPtr,IN_LENGTH_Z const int position,IN_DATALENGTH const int length)321 static int getMemoryBlock( INOUT STREAM *stream,
322 						   OUT_BUFFER_ALLOC_OPT( length ) void **dataPtrPtr,
323 						   IN_LENGTH_Z const int position,
324 						   IN_DATALENGTH const int length )
325 	{
326 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
327 	assert( isWritePtr( dataPtrPtr, sizeof( void * ) ) );
328 
329 	/* Check that the input parameters are in order */
330 	if( !isWritePtrConst( stream, sizeof( STREAM ) ) )
331 		retIntError();
332 
333 	REQUIRES( sanityCheck( stream ) && \
334 			  stream->type == STREAM_TYPE_MEMORY );
335 	REQUIRES_S( position >= 0 && position <= stream->bufSize && \
336 				position < MAX_BUFFER_SIZE );
337 	REQUIRES_S( length > 0 && length < MAX_BUFFER_SIZE );
338 
339 	/* Clear return value */
340 	*dataPtrPtr = NULL;
341 
342 	/* If there's a problem with the stream don't try to do anything */
343 	if( cryptStatusError( stream->status ) )
344 		return( stream->status );
345 
346 	/* Make sure that there's enough data available in the stream to satisfy
347 	   the request.  We check against bufSize rather than bufEnd since the
348 	   caller may be asking for access to all remaining data space in the
349 	   stream rather than just all data read/written so far */
350 	if( position + length < 0 || \
351 		position + length > stream->bufSize )
352 		return( sSetError( stream, CRYPT_ERROR_UNDERFLOW ) );
353 
354 	/* Return a pointer to the stream-internal buffer starting at location
355 	   'position' of length 'length' bytes */
356 	*dataPtrPtr = stream->buffer + position;
357 
358 	return( CRYPT_OK );
359 	}
360 
361 CHECK_RETVAL_RANGE_NOERROR( 0, MAX_BUFFER_SIZE ) STDC_NONNULL_ARG( ( 1 ) ) \
sMemDataLeft(const STREAM * stream)362 int sMemDataLeft( const STREAM *stream )
363 	{
364 	assert( isReadPtr( stream, sizeof( STREAM ) ) && \
365 			stream->type == STREAM_TYPE_MEMORY );
366 
367 	/* Check that the input parameters are in order */
368 	if( !isReadPtrConst( stream, sizeof( STREAM ) ) )
369 		retIntError();
370 
371 	/* We can't use REQUIRES_S() in this case because the stream is a const
372 	   parameter so instead we return a data-left size of zero */
373 	REQUIRES_EXT( ( sanityCheck( stream ) && \
374 					stream->type == STREAM_TYPE_MEMORY ), 0 );
375 
376 	/* If there's a problem with the stream don't try to do anything.
377 	   Unlike the standard stream read/write functions this function simply
378 	   returns a record of internal stream state rather than reporting the
379 	   status of a stream operation, so it's not generally checked by the
380 	   caller.  To indicate an error state the best that we can do is to
381 	   report zero bytes available, which will result in an underflow error
382 	   in the caller */
383 	if( cryptStatusError( stream->status ) )
384 		return( 0 );
385 
386 	return( stream->bufSize - stream->bufPos );
387 	}
388 
389 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
sMemGetDataBlock(INOUT STREAM * stream,OUT_BUFFER_ALLOC_OPT (dataSize)void ** dataPtrPtr,IN_DATALENGTH const int dataSize)390 int sMemGetDataBlock( INOUT STREAM *stream,
391 					  OUT_BUFFER_ALLOC_OPT( dataSize ) void **dataPtrPtr,
392 					  IN_DATALENGTH const int dataSize )
393 	{
394 	/* REQUIRES() checking done in getMemoryBlock() */
395 	assert( isReadPtr( stream, sizeof( STREAM ) ) && \
396 			stream->type == STREAM_TYPE_MEMORY );
397 	assert( isWritePtr( dataPtrPtr, sizeof( void * ) ) );
398 	assert( dataSize > 0 && dataSize < MAX_BUFFER_SIZE );
399 
400 	/* Clear return values */
401 	*dataPtrPtr = NULL;
402 
403 	return( getMemoryBlock( stream, dataPtrPtr, stream->bufPos, dataSize ) );
404 	}
405 
406 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
sMemGetDataBlockAbs(INOUT STREAM * stream,IN_DATALENGTH_Z const int position,OUT_BUFFER_ALLOC_OPT (dataSize)void ** dataPtrPtr,IN_DATALENGTH const int dataSize)407 int sMemGetDataBlockAbs( INOUT STREAM *stream,
408 						 IN_DATALENGTH_Z const int position,
409 						 OUT_BUFFER_ALLOC_OPT( dataSize ) void **dataPtrPtr,
410 						 IN_DATALENGTH const int dataSize )
411 	{
412 	/* REQUIRES() checking done in getMemoryBlock() */
413 	assert( isReadPtr( stream, sizeof( STREAM ) ) && \
414 			stream->type == STREAM_TYPE_MEMORY );
415 	assert( isWritePtr( dataPtrPtr, sizeof( void * ) ) );
416 	assert( position >= 0 && position <= stream->bufSize && \
417 			position < MAX_BUFFER_SIZE );
418 	assert( dataSize > 0 && dataSize < MAX_BUFFER_SIZE );
419 
420 	/* Clear return values */
421 	*dataPtrPtr = NULL;
422 
423 	return( getMemoryBlock( stream, dataPtrPtr, position, dataSize ) );
424 	}
425 
426 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
sMemGetDataBlockRemaining(INOUT STREAM * stream,OUT_BUFFER_ALLOC_OPT (* length)void ** dataPtrPtr,OUT_DATALENGTH_Z int * length)427 int sMemGetDataBlockRemaining( INOUT STREAM *stream,
428 							   OUT_BUFFER_ALLOC_OPT( *length ) void **dataPtrPtr,
429 							   OUT_DATALENGTH_Z int *length )
430 	{
431 	const int dataLeft = sMemDataLeft( stream );
432 	int status;
433 
434 	assert( isReadPtr( stream, sizeof( STREAM ) ) && \
435 			stream->type == STREAM_TYPE_MEMORY );
436 	assert( isWritePtr( dataPtrPtr, sizeof( void * ) ) );
437 	assert( isWritePtr( length, sizeof( int ) ) );
438 			/* REQUIRES() checking done in getMemoryBlock() */
439 
440 	/* Clear return values */
441 	*dataPtrPtr = NULL;
442 	*length = 0;
443 
444 	/* If there's no data remaining, return an underflow error */
445 	if( cryptStatusError( dataLeft ) )
446 		return( dataLeft );
447 	if( dataLeft <= 0 )
448 		return( CRYPT_ERROR_UNDERFLOW );
449 
450 	status = getMemoryBlock( stream, dataPtrPtr, stream->bufPos, dataLeft );
451 	if( cryptStatusError( status ) )
452 		return( status );
453 	*length = dataLeft;
454 
455 	return( CRYPT_OK );
456 	}
457