cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
misc_rw.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Miscellaneous (Non-ASN.1) Read/Write Routines *
4 * Copyright Peter Gutmann 1992-2007 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "bn.h"
11  #include "misc_rw.h"
12 #else
13  #include "crypt.h"
14  #include "bn/bn.h"
15  #include "enc_dec/misc_rw.h"
16 #endif /* Compiler-specific includes */
17 
18 /****************************************************************************
19 * *
20 * Utility Routines *
21 * *
22 ****************************************************************************/
23 
24 /* Read large integer data */
25 
26 typedef enum {
27  LENGTH_NONE, /* No length type */
28  LENGTH_16U, /* Unsigned int, 16-bit length */
29  LENGTH_16U_BITS, /* Unsigned int, 16-bit length, length in bits */
30  LENGTH_32, /* Signed int, 32-bit length */
31  LENGTH_LAST /* Last possible length type */
32  } LENGTH_TYPE;
33 
35 static int readInteger( INOUT STREAM *stream,
37  *integerLength ) void *integer,
39  IN_LENGTH_PKC const int minLength,
40  IN_LENGTH_PKC const int maxLength,
41  IN_ENUM( LENGTH ) const LENGTH_TYPE lengthType,
42  IN_ENUM_OPT( KEYSIZE_CHECK ) \
43  const KEYSIZE_CHECK_TYPE checkType )
44  {
45  int length;
46 
47  assert( isWritePtr( stream, sizeof( STREAM ) ) );
48  assert( integer == NULL || isWritePtr( integer, maxLength ) );
49  assert( isWritePtr( integerLength, sizeof( int ) ) );
50 
51  REQUIRES_S( minLength > 0 && minLength < maxLength && \
52  maxLength <= CRYPT_MAX_PKCSIZE );
53  REQUIRES_S( lengthType > LENGTH_NONE && lengthType < LENGTH_LAST );
54  REQUIRES_S( checkType >= KEYSIZE_CHECK_NONE && \
55  checkType < KEYSIZE_CHECK_LAST );
56 
57  /* Clear return values */
58  if( integer != NULL )
59  memset( integer, 0, min( 16, maxLength ) );
60  *integerLength = 0;
61 
62  /* Read the length and make sure that it's within range, with a 2-byte
63  allowance for extra zero-padding (the exact length will be checked
64  later after the padding is stripped) */
65  if( lengthType == LENGTH_16U || lengthType == LENGTH_16U_BITS )
66  length = readUint16( stream );
67  else
68  length = readUint32( stream );
69  if( cryptStatusError( length ) )
70  return( length );
71  if( lengthType == LENGTH_16U_BITS )
72  length = bitsToBytes( length );
73  if( checkType != KEYSIZE_CHECK_NONE )
74  {
75  REQUIRES( ( checkType == KEYSIZE_CHECK_ECC && \
76  minLength > bitsToBytes( 176 ) ) || \
77  ( checkType != KEYSIZE_CHECK_ECC && \
78  minLength > bitsToBytes( 256 ) ) );
79 
80  /* If the length is below the minimum allowed but still looks at
81  least vaguely valid, report it as a too-short key rather than a
82  bad data error */
83  if( checkType == KEYSIZE_CHECK_ECC )
84  {
85  if( isShortECCKey( length ) )
86  return( CRYPT_ERROR_NOSECURE );
87  }
88  else
89  {
90  if( isShortPKCKey( length ) )
91  return( CRYPT_ERROR_NOSECURE );
92  }
93  }
94  if( length < minLength || length > maxLength + 2 )
95  return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
96 
97  /* If we're reading a signed integer then the sign bit can't be set
98  since this would produce a negative value. This differs from the
99  ASN.1 code, where the incorrect setting of the sign bit is so common
100  that we always treat integers as unsigned */
101  if( lengthType == LENGTH_32 && ( sPeek( stream ) & 0x80 ) )
102  return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
103 
104  /* Skip possible leading-zero padding and repeat the length check once
105  the zero-padding has been adjusted */
106  while( length > 0 && sPeek( stream ) == 0 )
107  {
108  int status;
109 
110  status = sgetc( stream );
111  if( cryptStatusError( status ) )
112  return( status );
113  length--;
114  }
115  if( checkType != KEYSIZE_CHECK_NONE )
116  {
117  /* Repeat the earlier check on the adjusted value */
118  if( checkType == KEYSIZE_CHECK_ECC )
119  {
120  if( isShortECCKey( length ) )
121  return( CRYPT_ERROR_NOSECURE );
122  }
123  else
124  {
125  if( isShortPKCKey( length ) )
126  return( CRYPT_ERROR_NOSECURE );
127  }
128  }
129  if( length < minLength || length > maxLength )
130  return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
131 
132  /* Read the value */
133  *integerLength = length;
134  if( integer == NULL )
135  return( sSkip( stream, length ) );
136  return( sread( stream, integer, length ) );
137  }
138 
139 /****************************************************************************
140 * *
141 * Data Read Routines *
142 * *
143 ****************************************************************************/
144 
145 /* Read 16-, 32-, and 64-bit integer values */
146 
148 int readUint16( INOUT STREAM *stream )
149  {
150  BYTE buffer[ UINT16_SIZE + 8 ];
151  int value, status;
152 
153  assert( isWritePtr( stream, sizeof( STREAM ) ) );
154 
155  status = sread( stream, buffer, UINT16_SIZE );
156  if( cryptStatusError( status ) )
157  return( status );
158  value = ( ( int ) buffer[ 0 ] << 8 ) | buffer[ 1 ];
159  if( value < 0 || value > 0xFFFFL )
160  return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
161  return( value );
162  }
163 
165 int readUint32( INOUT STREAM *stream )
166  {
167  BYTE buffer[ UINT32_SIZE + 8 ];
168  int value, status;
169 
170  assert( isWritePtr( stream, sizeof( STREAM ) ) );
171 
172  status = sread( stream, buffer, UINT32_SIZE );
173  if( cryptStatusError( status ) )
174  return( status );
175  if( buffer[ 0 ] & 0x80 )
176  return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
177  value = ( ( int ) buffer[ 0 ] << 24 ) | \
178  ( ( int ) buffer[ 1 ] << 16 ) | \
179  ( ( int ) buffer[ 2 ] << 8 ) | \
180  buffer[ 3 ];
182  return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
183  return( value );
184  }
185 
187 int readUint64( INOUT STREAM *stream, OUT_INT_Z long *value )
188  {
189  BYTE buffer[ ( UINT64_SIZE / 2 ) + 8 ];
190  int localValue, status;
191 
192  assert( isWritePtr( stream, sizeof( STREAM ) ) );
193  assert( isWritePtr( value, sizeof( long ) ) );
194 
195  /* Clear return value */
196  *value = 0;
197 
198  status = sread( stream, buffer, UINT64_SIZE / 2 );
199  if( cryptStatusError( status ) )
200  return( status );
201  if( memcmp( buffer, "\x00\x00\x00\x00", UINT64_SIZE / 2 ) )
202  return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
203  status = localValue = readUint32( stream );
204  if( cryptStatusError( status ) )
205  return( status );
206  *value = localValue;
207 
208  return( CRYPT_OK );
209  }
210 
211 /* Read 32- and 64-bit time values. Note that we can't just call down
212  directly to readUint32() for these since time_t may be unsigned or of a
213  different integral size than int. In addition we have to be careful
214  about the sanity check in readUint32() against MAX_INTLENGTH, which
215  equates to the value 0x7EFFFFFF ~= mid-2037, so that dates after this
216  point will fail the range check. However this is only six months before
217  the hard limit of 2038 anyway, and hopefully by this time we'll be using
218  64-bit time_t's and won't have to worry about this range limit any
219  more */
220 
221 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
222 static int readTime( INOUT STREAM *stream, OUT time_t *timeVal,
223  const BOOLEAN is64bit )
224  {
225  int value = DUMMY_INIT, status;
226 
227  assert( isWritePtr( stream, sizeof( STREAM ) ) );
228  assert( isWritePtr( timeVal, sizeof( time_t ) ) );
229 
230  /* Clear return value */
231  *timeVal = 0;
232 
233  if( is64bit )
234  {
235  long longValue;
236 
237  status = readUint64( stream, &longValue );
238  if( cryptStatusOK( status ) )
239  value = ( int ) longValue;
240  }
241  else
242  status = value = readUint32( stream );
243  if( cryptStatusError( status ) )
244  return( status );
245  if( value < MIN_STORED_TIME_VALUE )
246  return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
247  *timeVal = ( time_t ) value;
248  return( CRYPT_OK );
249  }
250 
251 RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
252 int readUint32Time( INOUT STREAM *stream, OUT time_t *timeVal )
253  {
254  assert( isWritePtr( stream, sizeof( STREAM ) ) );
255  assert( isWritePtr( timeVal, sizeof( time_t ) ) );
256 
257  /* Clear return value */
258  *timeVal = 0;
259 
260  return( readTime( stream, timeVal, FALSE ) );
261  }
262 
263 RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
264 int readUint64Time( INOUT STREAM *stream, OUT time_t *timeVal )
265  {
266  assert( isWritePtr( stream, sizeof( STREAM ) ) );
267  assert( isWritePtr( timeVal, sizeof( time_t ) ) );
268 
269  /* Clear return value */
270  *timeVal = 0;
271 
272  return( readTime( stream, timeVal, TRUE ) );
273  }
274 
275 /* Read a string preceded by a 32-bit length */
276 
278 static int readData32( INOUT STREAM *stream,
280  IN_LENGTH_SHORT const int dataMaxLength,
282  const BOOLEAN includeLengthField )
283  {
284  BYTE *dataPtr = data;
285  const int headerSize = includeLengthField ? UINT32_SIZE : 0;
286  int length;
287 
288  assert( isWritePtr( stream, sizeof( STREAM ) ) );
289  assert( isWritePtr( data, dataMaxLength ) );
290  assert( isWritePtr( dataLength, sizeof( int ) ) );
291 
292  REQUIRES_S( dataMaxLength > 0 && dataMaxLength < MAX_INTLENGTH_SHORT );
293 
294  /* Clear return values */
295  memset( data, 0, min( 16, dataMaxLength ) );
296  *dataLength = 0;
297 
298  length = readUint32( stream );
299  if( length <= 0 )
300  {
301  /* Error or zero length. If it's zero length we don't return any
302  data */
303  return( length );
304  }
305  if( headerSize + length > dataMaxLength || length > MAX_INTLENGTH_SHORT )
306  return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
307  if( includeLengthField )
308  {
309  dataPtr[ 0 ] = ( length >> 24 ) & 0xFF;
310  dataPtr[ 1 ] = ( length >> 16 ) & 0xFF;
311  dataPtr[ 2 ] = ( length >> 8 ) & 0xFF;
312  dataPtr[ 3 ] = length & 0xFF;
313  }
314  *dataLength = headerSize + length;
315  return( sread( stream, dataPtr + headerSize, length ) );
316  }
317 
318 RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
319 int readString32( INOUT STREAM *stream,
321  *stringLength ) void *string,
322  IN_LENGTH_SHORT const int stringMaxLength,
324  {
325  assert( isWritePtr( stream, sizeof( STREAM ) ) );
326  assert( isWritePtr( string, stringMaxLength ) );
327  assert( isWritePtr( stringLength, sizeof( int ) ) );
328 
329  REQUIRES_S( stringMaxLength > 0 && stringMaxLength < MAX_INTLENGTH_SHORT );
330 
331  /* Read the string, limiting the size to the maximum buffer size */
332  return( readData32( stream, string, stringMaxLength, stringLength, FALSE ) );
333  }
334 
335 /* Read a raw object preceded by a 32-bit length */
336 
337 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
338 int readRawObject32( INOUT STREAM *stream,
339  OUT_BUFFER( bufferMaxLength, *bufferLength ) void *buffer,
341  const int bufferMaxLength,
343  {
344  assert( isWritePtr( stream, sizeof( STREAM ) ) );
345  assert( isWritePtr( buffer, bufferMaxLength ) );
346  assert( isWritePtr( bufferLength, sizeof( int ) ) );
347 
348  REQUIRES_S( bufferMaxLength >= UINT32_SIZE + 1 && \
349  bufferMaxLength < MAX_INTLENGTH_SHORT );
350 
351  /* Read the string, limiting the size to the maximum buffer size */
352  return( readData32( stream, buffer, bufferMaxLength, bufferLength,
353  TRUE ) );
354  }
355 
356 /* Read a universal type and discard it, used to skip unknown or unwanted
357  types */
358 
360 static int readUniversal( INOUT STREAM *stream,
361  IN_ENUM( LENGTH ) const LENGTH_TYPE lengthType )
362  {
363  int length, status;
364 
365  assert( isWritePtr( stream, sizeof( STREAM ) ) );
366 
367  REQUIRES_S( lengthType == LENGTH_16U || lengthType == LENGTH_32 );
368 
369  /* Read the length and skip the data */
370  if( lengthType == LENGTH_16U )
371  status = length = readUint16( stream );
372  else
373  status = length = readUint32( stream );
374  if( cryptStatusError( status ) )
375  return( status );
376  if( length <= 0 )
377  return( CRYPT_OK ); /* Zero-length data */
378  return( sSkip( stream, length ) );
379  }
380 
381 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
382 int readUniversal16( INOUT STREAM *stream )
383  {
384  return( readUniversal( stream, LENGTH_16U ) );
385  }
386 
387 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
388 int readUniversal32( INOUT STREAM *stream )
389  {
390  return( readUniversal( stream, LENGTH_32 ) );
391  }
392 
393 /* Read (large) integers in various formats */
394 
395 RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
396 int readInteger16U( INOUT STREAM *stream,
397  OUT_BUFFER_OPT( maxLength, \
398  *integerLength ) void *integer,
399  OUT_LENGTH_PKC_Z int *integerLength,
400  IN_LENGTH_PKC const int minLength,
401  IN_LENGTH_PKC const int maxLength )
402  {
403  return( readInteger( stream, integer, integerLength, minLength,
404  maxLength, LENGTH_16U, KEYSIZE_CHECK_NONE ) );
405  }
406 
407 RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
408 int readInteger16Ubits( INOUT STREAM *stream,
409  OUT_BUFFER_OPT( maxLength, \
410  *integerLength ) void *integer,
411  OUT_LENGTH_PKC_Z int *integerLength,
412  IN_LENGTH_PKC const int minLength,
413  IN_LENGTH_PKC const int maxLength )
414  {
415  return( readInteger( stream, integer, integerLength, minLength,
416  maxLength, LENGTH_16U_BITS, KEYSIZE_CHECK_NONE ) );
417  }
418 
419 RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
420 int readInteger32( INOUT STREAM *stream,
421  OUT_BUFFER_OPT( maxLength, \
422  *integerLength ) void *integer,
423  OUT_LENGTH_PKC_Z int *integerLength,
424  IN_LENGTH_PKC const int minLength,
425  IN_LENGTH_PKC const int maxLength )
426  {
427  return( readInteger( stream, integer, integerLength, minLength,
428  maxLength, LENGTH_32, KEYSIZE_CHECK_NONE ) );
429  }
430 
431 /* Special-case large integer read routines that explicitly check for a too-
432  short key and return CRYPT_ERROR_NOSECURE rather than the
433  CRYPT_ERROR_BADDATA that'd otherwise be returned */
434 
435 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
436 int readInteger16UChecked( INOUT STREAM *stream,
437  OUT_BUFFER_OPT( maxLength, *integerLength ) \
438  void *integer,
439  OUT_LENGTH_PKC_Z int *integerLength,
440  IN_LENGTH_PKC const int minLength,
441  IN_LENGTH_PKC const int maxLength )
442  {
443  return( readInteger( stream, integer, integerLength, minLength,
444  maxLength, LENGTH_16U, KEYSIZE_CHECK_PKC ) );
445  }
446 
447 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
448 int readInteger32Checked( INOUT STREAM *stream,
449  OUT_BUFFER_OPT( maxLength, *integerLength ) \
450  void *integer,
451  OUT_LENGTH_PKC_Z int *integerLength,
452  IN_LENGTH_PKC const int minLength,
453  IN_LENGTH_PKC const int maxLength )
454  {
455  /* Perform the appropriate length check for the algorithm type. The
456  way that this is currently done is a bit of a nasty hack, but it
457  saves having to create a special-case ECC-only function that's only
458  used in one place */
459  if( minLength == MIN_PKCSIZE_ECCPOINT && \
460  maxLength == MAX_PKCSIZE_ECCPOINT )
461  {
462  return( readInteger( stream, integer, integerLength, minLength,
463  maxLength, LENGTH_32, KEYSIZE_CHECK_ECC ) );
464  }
465  return( readInteger( stream, integer, integerLength, minLength,
466  maxLength, LENGTH_32, KEYSIZE_CHECK_PKC ) );
467  }
468 
469 #ifdef USE_PKC
470 
471 /* Read integers as bignums in various formats */
472 
473 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
474 static int readBignumInteger( INOUT STREAM *stream,
475  INOUT TYPECAST( BIGNUM * ) void *bignum,
476  IN_LENGTH_PKC const int minLength,
477  IN_LENGTH_PKC const int maxLength,
478  IN_OPT TYPECAST( BIGNUM * ) const void *maxRange,
479  IN_ENUM( LENGTH ) const LENGTH_TYPE lengthType,
480  IN_ENUM_OPT( KEYSIZE_CHECK ) \
481  const KEYSIZE_CHECK_TYPE checkType )
482  {
483  BYTE buffer[ CRYPT_MAX_PKCSIZE + 8 ];
484  int length, status;
485 
486  assert( isWritePtr( stream, sizeof( STREAM ) ) );
487  assert( isWritePtr( bignum, sizeof( BIGNUM ) ) );
488  assert( maxRange == NULL || isReadPtr( maxRange, sizeof( BIGNUM ) ) );
489 
490  REQUIRES_S( minLength > 0 && minLength < maxLength && \
491  maxLength <= CRYPT_MAX_PKCSIZE );
492  REQUIRES_S( lengthType > LENGTH_NONE && lengthType < LENGTH_LAST );
493  REQUIRES( checkType >= KEYSIZE_CHECK_NONE && \
494  checkType < KEYSIZE_CHECK_LAST );
495 
496  /* Read the integer data */
497  status = readInteger( stream, buffer, &length, minLength, maxLength,
498  lengthType, checkType );
499  if( cryptStatusError( status ) )
500  return( status );
501 
502  /* Convert the value to a bignum. Note that we use the checkKEYSIZE
503  parameter for both readInteger() and importBignum(), since the
504  former merely checks the byte count while the latter actually parses
505  and processes the bignum */
506  status = importBignum( bignum, buffer, length, minLength, maxLength,
507  maxRange, checkType );
508  if( cryptStatusError( status ) )
509  status = sSetError( stream, status );
510  zeroise( buffer, CRYPT_MAX_PKCSIZE );
511  return( status );
512  }
513 
514 RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
515 int readBignumInteger16U( INOUT STREAM *stream,
516  INOUT TYPECAST( BIGNUM * ) void *bignum,
517  IN_LENGTH_PKC const int minLength,
518  IN_LENGTH_PKC const int maxLength,
519  IN_OPT TYPECAST( BIGNUM * ) const void *maxRange )
520  {
521  return( readBignumInteger( stream, bignum, minLength, maxLength,
522  maxRange, LENGTH_16U, KEYSIZE_CHECK_NONE ) );
523  }
524 
525 RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
526 int readBignumInteger16Ubits( INOUT STREAM *stream,
527  INOUT TYPECAST( BIGNUM * ) void *bignum,
528  IN_LENGTH_PKC const int minBits,
529  IN_LENGTH_PKC const int maxBits,
530  IN_OPT TYPECAST( BIGNUM * ) const void *maxRange )
531  {
532  return( readBignumInteger( stream, bignum, bitsToBytes( minBits ),
533  bitsToBytes( maxBits ), maxRange,
535  }
536 
537 RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
538 int readBignumInteger32( INOUT STREAM *stream,
539  INOUT TYPECAST( BIGNUM * ) void *bignum,
540  IN_LENGTH_PKC const int minLength,
541  IN_LENGTH_PKC const int maxLength,
542  IN_OPT TYPECAST( BIGNUM * ) const void *maxRange )
543  {
544  return( readBignumInteger( stream, bignum, minLength, maxLength,
545  maxRange, LENGTH_32, KEYSIZE_CHECK_NONE ) );
546  }
547 
548 /* Special-case bignum read routines that explicitly check for a too-short
549  key and return CRYPT_ERROR_NOSECURE rather than the CRYPT_ERROR_BADDATA
550  that'd otherwise be returned */
551 
552 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
553 int readBignumInteger16UChecked( INOUT STREAM *stream,
554  INOUT TYPECAST( BIGNUM * ) void *bignum,
555  IN_LENGTH_PKC const int minLength,
556  IN_LENGTH_PKC const int maxLength )
557  {
558  return( readBignumInteger( stream, bignum, minLength, maxLength, NULL,
560  }
561 
562 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
563 int readBignumInteger16UbitsChecked( INOUT STREAM *stream,
564  INOUT TYPECAST( BIGNUM * ) void *bignum,
565  IN_LENGTH_PKC const int minBits,
566  IN_LENGTH_PKC const int maxBits )
567  {
568  return( readBignumInteger( stream, bignum, bitsToBytes( minBits ),
569  bitsToBytes( maxBits ), NULL,
571  }
572 
573 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
574 int readBignumInteger32Checked( INOUT STREAM *stream,
575  INOUT TYPECAST( BIGNUM * ) void *bignum,
576  IN_LENGTH_PKC const int minLength,
577  IN_LENGTH_PKC const int maxLength )
578  {
579  return( readBignumInteger( stream, bignum, minLength, maxLength,
580  NULL, LENGTH_32, KEYSIZE_CHECK_PKC ) );
581  }
582 #endif /* USE_PKC */
583 
584 /****************************************************************************
585 * *
586 * Data Write Routines *
587 * *
588 ****************************************************************************/
589 
590 /* Write 16-, 32- and 64-bit integer values */
591 
592 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
593 int writeUint16( INOUT STREAM *stream,
594  IN_RANGE( 0, 0xFFFF ) const int value )
595  {
596  assert( isWritePtr( stream, sizeof( STREAM ) ) );
597 
598  REQUIRES_S( value >= 0 && value <= 0xFFFFL );
599 
600  sputc( stream, ( value >> 8 ) & 0xFF );
601  return( sputc( stream, value & 0xFF ) );
602  }
603 
604 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
605 int writeUint32( INOUT STREAM *stream, IN_INT_Z const long value )
606  {
607  BYTE buffer[ UINT32_SIZE + 8 ];
608 
609  assert( isWritePtr( stream, sizeof( STREAM ) ) );
610 
611  REQUIRES_S( value >= 0 && value < MAX_INTLENGTH );
612 
613  buffer[ 0 ] = ( value >> 24 ) & 0xFF;
614  buffer[ 1 ] = ( value >> 16 ) & 0xFF;
615  buffer[ 2 ] = ( value >> 8 ) & 0xFF;
616  buffer[ 3 ] = value & 0xFF;
617  return( swrite( stream, buffer, UINT32_SIZE ) );
618  }
619 
620 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
621 int writeUint64( INOUT STREAM *stream, IN_INT_Z const long value )
622  {
623  assert( isWritePtr( stream, sizeof( STREAM ) ) );
624 
625  REQUIRES_S( value >= 0 && value < MAX_INTLENGTH );
626 
627  swrite( stream, "\x00\x00\x00\x00", UINT64_SIZE / 2 );
628  return( writeUint32( stream, value ) );
629  }
630 
631 /* Write 32- and 64-bit time values */
632 
633 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
634 int writeUint32Time( INOUT STREAM *stream, const time_t timeVal )
635  {
636  REQUIRES_S( timeVal >= MIN_TIME_VALUE );
637 
638  return( writeUint32( stream, ( int ) timeVal ) );
639  }
640 
641 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
642 int writeUint64Time( INOUT STREAM *stream, const time_t timeVal )
643  {
644  REQUIRES_S( timeVal >= MIN_TIME_VALUE );
645 
646  return( writeUint64( stream, ( int ) timeVal ) );
647  }
648 
649 /* Write a string preceded by a 32-bit length */
650 
651 RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
652 int writeString32( INOUT STREAM *stream,
653  IN_BUFFER( stringLength ) const void *string,
654  IN_LENGTH_SHORT const int stringLength )
655  {
656  assert( isWritePtr( stream, sizeof( STREAM ) ) );
657  assert( isReadPtr( string, stringLength ) );
658 
659  REQUIRES_S( stringLength > 0 && stringLength < MAX_INTLENGTH );
660 
661  writeUint32( stream, stringLength );
662  return( swrite( stream, string, stringLength ) );
663  }
664 
665 /* Write large integers in various formats */
666 
667 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
668 static int writeInteger( INOUT STREAM *stream,
669  IN_BUFFER( integerLength ) const void *integer,
670  IN_LENGTH_PKC const int integerLength,
671  IN_ENUM( LENGTH ) const LENGTH_TYPE lengthType )
672  {
673  const BYTE *intPtr = integer;
674  int length = integerLength;
675 
676  assert( isWritePtr( stream, sizeof( STREAM ) ) );
677  assert( isReadPtr( integer, integerLength ) );
678 
679  REQUIRES_S( integerLength > 0 && integerLength <= CRYPT_MAX_PKCSIZE );
680  REQUIRES_S( lengthType > LENGTH_NONE && lengthType < LENGTH_LAST );
681 
682  /* Integers may be passed to us from higher-level code with leading
683  zeroes as part of the encoding. Before we write them out we strip
684  out any superfluous leading zeroes that may be present */
685  while( length > 0 && *intPtr == 0 )
686  {
687  intPtr++;
688  length--;
689  }
690  ENSURES( length > 0 );
691 
692  switch( lengthType )
693  {
694  case LENGTH_16U:
695  writeUint16( stream, length );
696  break;
697 
698  case LENGTH_16U_BITS:
699  writeUint16( stream, bytesToBits( length ) );
700  break;
701 
702  case LENGTH_32:
703  {
704  const BOOLEAN leadingOneBit = *intPtr & 0x80;
705 
706  writeUint32( stream, length + ( leadingOneBit ? 1 : 0 ) );
707  if( leadingOneBit )
708  sputc( stream, 0 ); /* MPIs are signed values */
709  break;
710  }
711 
712  default:
713  retIntError_Stream( stream );
714  }
715  return( swrite( stream, intPtr, length ) );
716  }
717 
718 RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
719 int writeInteger16U( INOUT STREAM *stream,
720  IN_BUFFER( integerLength ) const void *integer,
721  IN_LENGTH_PKC const int integerLength )
722  {
723  return( writeInteger( stream, integer, integerLength, LENGTH_16U ) );
724  }
725 
726 RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
727 int writeInteger16Ubits( INOUT STREAM *stream,
728  IN_BUFFER( integerLength ) const void *integer,
729  IN_LENGTH_PKC const int integerLength )
730  {
731  return( writeInteger( stream, integer, integerLength, LENGTH_16U_BITS ) );
732  }
733 
734 RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
735 int writeInteger32( INOUT STREAM *stream,
736  IN_BUFFER( integerLength ) const void *integer,
737  IN_LENGTH_PKC const int integerLength )
738  {
739  return( writeInteger( stream, integer, integerLength, LENGTH_32 ) );
740  }
741 
742 #ifdef USE_PKC
743 
744 /* Write integers from bignums in various formats */
745 
747 int sizeofBignumInteger32( const void *bignum )
748  {
749  assert( isReadPtr( bignum, sizeof( BIGNUM ) ) );
750 
751  return( UINT32_SIZE + BN_high_bit( ( BIGNUM * ) bignum ) + \
752  BN_num_bytes( bignum ) );
753  }
754 
755 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
756 static int writeBignumInteger( INOUT STREAM *stream,
757  TYPECAST( BIGNUM * ) const void *bignum,
758  IN_ENUM( LENGTH ) const LENGTH_TYPE lengthType )
759  {
760  BYTE buffer[ CRYPT_MAX_PKCSIZE + 8 ];
761  int bnLength, status;
762 
763  assert( isWritePtr( stream, sizeof( STREAM ) ) );
764  assert( isReadPtr( bignum, sizeof( BIGNUM ) ) );
765 
766  REQUIRES_S( lengthType > LENGTH_NONE && lengthType < LENGTH_LAST );
767 
768  status = exportBignum( buffer, CRYPT_MAX_PKCSIZE, &bnLength, bignum );
769  ENSURES_S( cryptStatusOK( status ) );
770  if( lengthType == LENGTH_16U_BITS )
771  {
772  /* We can't call down to writeInteger() from here because we need to
773  write a precise length in bits rather than a value reconstructed
774  from the byte count. This also means that we can't easily
775  perform the leading-zero truncation that writeInteger() does
776  without a lot of low-level fiddling that duplicates code in
777  writeInteger() */
778  writeUint16( stream, BN_num_bits( bignum ) );
779  status = swrite( stream, buffer, bnLength );
780  }
781  else
782  status = writeInteger( stream, buffer, bnLength, lengthType );
783  zeroise( buffer, CRYPT_MAX_PKCSIZE );
784  return( status );
785  }
786 
787 RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
788 int writeBignumInteger16U( INOUT STREAM *stream,
789  TYPECAST( BIGNUM * ) const void *bignum )
790  {
791  return( writeBignumInteger( stream, bignum, LENGTH_16U ) );
792  }
793 
794 RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
795 int writeBignumInteger16Ubits( INOUT STREAM *stream,
796  TYPECAST( BIGNUM * ) const void *bignum )
797  {
798  return( writeBignumInteger( stream, bignum, LENGTH_16U_BITS ) );
799  }
800 
801 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
802 int writeBignumInteger32( INOUT STREAM *stream,
803  TYPECAST( BIGNUM * ) const void *bignum )
804  {
805  return( writeBignumInteger( stream, bignum, LENGTH_32 ) );
806  }
807 #endif /* USE_PKC */