cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
memory.c
Go to the documentation of this file.
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 
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_INTLENGTH )
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_INTLENGTH )
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 
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 
102 static int checkMemoryStreamParams( INOUT STREAM *stream,
103  IN_BUFFER( length ) const void *buffer,
104  IN_LENGTH_Z const int length )
105  {
106  /* We don't use a REQUIRES() predicate here for the reasons given in the
107  comments above */
108  assert( isWritePtr( stream, sizeof( STREAM ) ) );
109  assert( length > 0 && length < MAX_INTLENGTH );
110  assert( isReadPtr( buffer, length ) );
111 
112  /* If there's a problem with the parameters, return an error code but
113  also make it a (non-readable, non-writeable) null stream with the
114  error state set via retIntError_Stream() so that it can be safely
115  used */
116  if( length < 1 || length >= MAX_INTLENGTH || \
117  !isReadPtr( buffer, length ) )
118  {
119  stream->type = STREAM_TYPE_NULL;
120  stream->flags = STREAM_FLAG_READONLY;
121  retIntError_Stream( stream );
122  }
123 
124  return( CRYPT_OK );
125  }
126 
127 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
128 static int shutdownMemoryStream( INOUT STREAM *stream,
129  const BOOLEAN clearStreamBuffer )
130  {
131  assert( isWritePtr( stream, sizeof( STREAM ) ) );
132 
133  REQUIRES( stream->type == STREAM_TYPE_NULL || \
134  stream->type == STREAM_TYPE_MEMORY );
135 
136  /* Check that the input parameters are in order */
137  if( !isWritePtrConst( stream, sizeof( STREAM ) ) )
138  retIntError();
139 
140  /* Clear the stream structure */
141  if( clearStreamBuffer && stream->buffer != NULL && stream->bufEnd > 0 )
142  zeroise( stream->buffer, stream->bufEnd );
143  zeroise( stream, sizeof( STREAM ) );
144 
145  return( CRYPT_OK );
146  }
147 
148 /* Open/close a memory stream or a null stream that serves as a data sink,
149  which is useful for implementing sizeof() functions by writing data to
150  null streams. If calling sMemOpenOpt() and the buffer parameter is NULL
151  and the length is zero this creates a null stream, otherwise is creates
152  a standard memory stream. This is useful for functions that follow the
153  convention of being passed a null buffer for a length check and a non-
154  null buffer to produce output.
155 
156  We don't use REQUIRES() predicates for these functions for the reasons
157  given in the comments in initMemoryStream() */
158 
159 RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
160 int sMemOpen( OUT STREAM *stream,
161  OUT_BUFFER_FIXED( length ) void *buffer,
162  IN_LENGTH const int length )
163  {
164  int status;
165 
166  /* REQUIRES() checking done in initMemoryStream() */
167  assert( isWritePtr( stream, sizeof( STREAM ) ) );
168  assert( isWritePtr( buffer, length ) );
169  assert( length > 0 && length < MAX_INTLENGTH );
170 
171  /* Initialise the memory stream. Static analysis tools may warn about
172  the use of uninitialised memory in checkMemoryStreamParams(),
173  unfortunately this can't be avoided because we need to be able to
174  access it for isReadPtr() even though we aren't actually reading
175  from it */
176  status = initMemoryStream( stream, FALSE );
177  if( cryptStatusOK( status ) )
178  status = checkMemoryStreamParams( stream, buffer, length );
179  if( cryptStatusError( status ) )
180  return( status );
181  stream->buffer = buffer;
182  stream->bufSize = length;
183 
184  /* Clear the stream buffer. Since this can be arbitrarily large we only
185  clear the entire buffer in the debug version */
186 #ifdef NDEBUG
187  memset( stream->buffer, 0, min( 16, stream->bufSize ) );
188 #else
189  memset( stream->buffer, 0, stream->bufSize );
190 #endif /* NDEBUG */
191 
192  return( CRYPT_OK );
193  }
194 
195 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
196 int sMemNullOpen( STREAM *stream )
197  {
198  int status;
199 
200  assert( isWritePtr( stream, sizeof( STREAM ) ) );
201 
202  /* Initialise the memory stream */
203  status = initMemoryStream( stream, TRUE );
204  if( cryptStatusError( status ) )
205  return( status );
206 
207  return( CRYPT_OK );
208  }
209 
210 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
211 int sMemOpenOpt( OUT STREAM *stream,
212  OUT_BUFFER_OPT_FIXED( length ) void *buffer,
213  IN_LENGTH_Z const int length )
214  {
215  assert( isWritePtr( stream, sizeof( STREAM ) ) );
216  assert( ( buffer == NULL && length == 0 ) || \
217  isReadPtr( buffer, length ) );
218 
219  /* Note that the following must be given as 'buffer == NULL' without an
220  additional 'length == 0' because static-analysis tools can't make the
221  connection between 'buffer' and 'length' and will warn that the value
222  passed to sMemOpen() may be NULL */
223  if( buffer == NULL )
224  return( sMemNullOpen( stream ) );
225  return( sMemOpen( stream, buffer, length ) );
226  }
227 
228 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
229 int sMemClose( STREAM *stream )
230  {
231  assert( isWritePtr( stream, sizeof( STREAM ) ) );
232 
233  REQUIRES( sanityCheck( stream ) );
234  REQUIRES( !( stream->flags & STREAM_FLAG_READONLY ) );
235 
236  return( shutdownMemoryStream( stream, TRUE ) );
237  }
238 
239 /* Connect/disconnect a memory stream without destroying the buffer
240  contents */
241 
242 RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
243 int sMemConnect( OUT STREAM *stream,
244  IN_BUFFER( length ) const void *buffer,
245  IN_LENGTH const int length )
246  {
247  int status;
248 
249  assert( isWritePtr( stream, sizeof( STREAM ) ) );
250  assert( length > 0 && length < MAX_INTLENGTH );
251  assert( isReadPtr( buffer, length ) );
252 
253  /* Initialise the memory stream. We don't use a REQUIRES() predicate
254  for the reasons given in the comments in initMemoryStream() */
255  status = initMemoryStream( stream, FALSE );
256  if( cryptStatusOK( status ) )
257  status = checkMemoryStreamParams( stream, buffer, length );
258  if( cryptStatusError( status ) )
259  return( status );
260  stream->buffer = ( void * ) buffer;
261  stream->bufSize = length;
262 
263  /* Initialise further portions of the stream structure. This is a read-
264  only stream so what's in the buffer at the start is all we'll ever
265  get */
266  stream->bufEnd = length;
267  stream->flags = STREAM_FLAG_READONLY;
268 
269  return( CRYPT_OK );
270  }
271 
272 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
273 int sMemDisconnect( INOUT STREAM *stream )
274  {
275  assert( isWritePtr( stream, sizeof( STREAM ) ) );
276 
277  REQUIRES( sanityCheck( stream ) );
278 
279  return( shutdownMemoryStream( stream, FALSE ) );
280  }
281 
282 /****************************************************************************
283 * *
284 * Direct Access Functions *
285 * *
286 ****************************************************************************/
287 
288 /* Memory stream direct-access functions, used when the contents of a memory
289  stream need to be encrypted/decrypted/signed/MACd. The basic
290  sMemGetDataBlock() returns a data block of a given size from the current
291  stream position, sMemGetDataBlockAbs() returns a data block from the
292  given stream position, and sMemGetDataBlockRemaining() returns a data
293  block containing all remaining data available in the stream */
294 
295 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
296 static int getMemoryBlock( INOUT STREAM *stream,
297  OUT_BUFFER_ALLOC_OPT( length ) void **dataPtrPtr,
298  IN_LENGTH_Z const int position,
299  IN_LENGTH const int length )
300  {
301  assert( isWritePtr( stream, sizeof( STREAM ) ) );
302  assert( isWritePtr( dataPtrPtr, sizeof( void * ) ) );
303 
304  /* Check that the input parameters are in order */
305  if( !isWritePtrConst( stream, sizeof( STREAM ) ) )
306  retIntError();
307 
308  REQUIRES( sanityCheck( stream ) && \
309  stream->type == STREAM_TYPE_MEMORY );
310  REQUIRES_S( position >= 0 && position <= stream->bufSize );
311  REQUIRES_S( length > 0 && length < MAX_INTLENGTH );
312 
313  /* Clear return value */
314  *dataPtrPtr = NULL;
315 
316  /* If there's a problem with the stream don't try to do anything */
317  if( cryptStatusError( stream->status ) )
318  return( stream->status );
319 
320  /* Make sure that there's enough data available in the stream to satisfy
321  the request. We check against bufSize rather than bufEnd since the
322  caller may be asking for access to all remaining data space in the
323  stream rather than just all data read/written so far */
324  if( position + length < 0 || \
325  position + length > stream->bufSize )
326  return( sSetError( stream, CRYPT_ERROR_UNDERFLOW ) );
327 
328  /* Return a pointer to the stream-internal buffer starting at location
329  'position' of length 'length' bytes */
330  *dataPtrPtr = stream->buffer + position;
331 
332  return( CRYPT_OK );
333  }
334 
336 int sMemDataLeft( const STREAM *stream )
337  {
338  assert( isReadPtr( stream, sizeof( STREAM ) ) && \
339  stream->type == STREAM_TYPE_MEMORY );
340 
341  /* Check that the input parameters are in order */
342  if( !isReadPtrConst( stream, sizeof( STREAM ) ) )
343  retIntError();
344 
345  /* We can't use REQUIRES_S() in this case because the stream is a const
346  parameter so instead we return a data-left size of zero */
347  REQUIRES_EXT( ( sanityCheck( stream ) && \
348  stream->type == STREAM_TYPE_MEMORY ), 0 );
349 
350  /* If there's a problem with the stream don't try to do anything.
351  Unlike the standard stream read/write functions this function simply
352  returns a record of internal stream state rather than reporting the
353  status of a stream operation, so it's not generally checked by the
354  caller. To indicate an error state the best that we can do is to
355  report zero bytes available, which will result in an underflow error
356  in the caller */
357  if( cryptStatusError( stream->status ) )
358  return( 0 );
359 
360  return( stream->bufSize - stream->bufPos );
361  }
362 
363 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
364 int sMemGetDataBlock( INOUT STREAM *stream,
365  OUT_BUFFER_ALLOC_OPT( dataSize ) void **dataPtrPtr,
366  IN_LENGTH const int dataSize )
367  {
368  /* REQUIRES() checking done in getMemoryBlock() */
369  assert( isReadPtr( stream, sizeof( STREAM ) ) && \
370  stream->type == STREAM_TYPE_MEMORY );
371  assert( isWritePtr( dataPtrPtr, sizeof( void * ) ) );
372  assert( dataSize > 0 && dataSize < MAX_INTLENGTH );
373 
374  /* Clear return values */
375  *dataPtrPtr = NULL;
376 
377  return( getMemoryBlock( stream, dataPtrPtr, stream->bufPos, dataSize ) );
378  }
379 
381 int sMemGetDataBlockAbs( INOUT STREAM *stream,
382  IN_LENGTH_Z const int position,
383  OUT_BUFFER_ALLOC_OPT( dataSize ) void **dataPtrPtr,
384  IN_LENGTH const int dataSize )
385  {
386  /* REQUIRES() checking done in getMemoryBlock() */
387  assert( isReadPtr( stream, sizeof( STREAM ) ) && \
388  stream->type == STREAM_TYPE_MEMORY );
389  assert( isWritePtr( dataPtrPtr, sizeof( void * ) ) );
390  assert( position >= 0 && position < stream->bufSize );
391  assert( dataSize > 0 && dataSize < MAX_INTLENGTH );
392 
393  /* Clear return values */
394  *dataPtrPtr = NULL;
395 
396  return( getMemoryBlock( stream, dataPtrPtr, position, dataSize ) );
397  }
398 
400 int sMemGetDataBlockRemaining( INOUT STREAM *stream,
401  OUT_BUFFER_ALLOC_OPT( *length ) void **dataPtrPtr,
402  OUT_LENGTH_Z int *length )
403  {
404  const int dataLeft = sMemDataLeft( stream );
405  int status;
406 
407  assert( isReadPtr( stream, sizeof( STREAM ) ) && \
408  stream->type == STREAM_TYPE_MEMORY );
409  assert( isWritePtr( dataPtrPtr, sizeof( void * ) ) );
410  assert( isWritePtr( length, sizeof( int ) ) );
411  /* REQUIRES() checking done in getMemoryBlock() */
412 
413  /* Clear return values */
414  *dataPtrPtr = NULL;
415  *length = 0;
416 
417  /* If there's no data remaining, return an underflow error */
418  if( cryptStatusError( dataLeft ) )
419  return( dataLeft );
420  if( dataLeft <= 0 )
421  return( CRYPT_ERROR_UNDERFLOW );
422 
423  status = getMemoryBlock( stream, dataPtrPtr, stream->bufPos, dataLeft );
424  if( cryptStatusError( status ) )
425  return( status );
426  *length = dataLeft;
427 
428  return( CRYPT_OK );
429  }