cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
asn1_wr.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * ASN.1 Write Routines *
4 * Copyright Peter Gutmann 1992-2008 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "bn.h"
11  #include "asn1.h"
12 #else
13  #include "crypt.h"
14  #include "bn/bn.h"
15  #include "enc_dec/asn1.h"
16 #endif /* Compiler-specific includes */
17 
18 /****************************************************************************
19 * *
20 * Utility Routines *
21 * *
22 ****************************************************************************/
23 
24 /* Calculate the size of the encoded length octets */
25 
27 static int calculateLengthSize( IN_LENGTH_Z const long length )
28  {
29  REQUIRES( length >= 0 && length < MAX_INTLENGTH );
30 
31  /* Use the short form of the length octets if possible */
32  if( length <= 0x7F )
33  return( 1 );
34 
35  /* Use the long form of the length octets, a length-of-length followed
36  by an 8, 16, 24, or 32-bit length. We order the comparisons by
37  likelihood of occurrence, shorter lengths are far more common than
38  longer ones */
39  if( length <= 0xFF )
40  return( 1 + 1 );
41  if( length <= 0xFFFFL )
42  return( 1 + 2 );
43  return( 1 + ( ( length > 0xFFFFFFL ) ? 4 : 3 ) );
44  }
45 
46 /* Write the length octets for an ASN.1 item */
47 
49 static int writeLength( INOUT STREAM *stream, IN_LENGTH_Z const long length )
50  {
51  BYTE buffer[ 8 + 8 ];
52  const int noLengthOctets = ( length <= 0xFF ) ? 1 : \
53  ( length <= 0xFFFFL ) ? 2 : \
54  ( length <= 0xFFFFFFL ) ? 3 : 4;
55  int bufPos = 1;
56 
57  assert( isWritePtr( stream, sizeof( STREAM ) ) );
58 
59  REQUIRES_S( length >= 0 && length < MAX_INTLENGTH );
60 
61  /* Use the short form of the length octets if possible */
62  if( length <= 0x7F )
63  return( sputc( stream, length & 0xFF ) );
64 
65  /* Encode the number of length octets followed by the octets themselves */
66  buffer[ 0 ] = 0x80 | noLengthOctets;
67  if( noLengthOctets > 3 )
68  buffer[ bufPos++ ] = ( length >> 24 ) & 0xFF;
69  if( noLengthOctets > 2 )
70  buffer[ bufPos++ ] = ( length >> 16 ) & 0xFF;
71  if( noLengthOctets > 1 )
72  buffer[ bufPos++ ] = ( length >> 8 ) & 0xFF;
73  buffer[ bufPos++ ] = length & 0xFF;
74  return( swrite( stream, buffer, bufPos ) );
75  }
76 
77 /* Write a (non-bignum) numeric value, used by several routines. The
78  easiest way to do this is to encode the bytes starting from the LSB
79  and then output them in reverse order to get a big-endian encoding */
80 
82 static int writeNumeric( INOUT STREAM *stream, IN_INT const long integer )
83  {
84  BYTE buffer[ 16 + 8 ];
85  long intValue = integer;
86  int length = 0, i, iterationCount;
87 
88  assert( isWritePtr( stream, sizeof( STREAM ) ) );
89 
90  REQUIRES_S( integer >= 0 && integer < MAX_INTLENGTH );
91 
92  /* The value 0 is handled specially */
93  if( intValue == 0 )
94  return( swrite( stream, "\x01\x00", 2 ) );
95 
96  /* Assemble the encoded value in little-endian order */
97  if( intValue > 0 )
98  {
99  for( iterationCount = 0;
100  intValue > 0 && iterationCount < FAILSAFE_ITERATIONS_SMALL;
101  iterationCount++ )
102  {
103  buffer[ length++ ] = intValue & 0xFF;
104  intValue >>= 8;
105  }
106  ENSURES( iterationCount < FAILSAFE_ITERATIONS_SMALL );
107 
108  /* Make sure that we don't inadvertently set the sign bit if the
109  high bit of the value is set */
110  if( buffer[ length - 1 ] & 0x80 )
111  buffer[ length++ ] = 0x00;
112  }
113  else
114  {
115  /* Write a negative integer values. This code is never executed
116  (and is actually checked for by the precondition at the start of
117  this function), it's present only in case it's ever needed in the
118  future */
119  iterationCount = 0;
120  do
121  {
122  buffer[ length++ ] = intValue & 0xFF;
123  intValue >>= 8;
124  }
125  while( intValue != -1 && length < sizeof( int ) && \
126  iterationCount++ < FAILSAFE_ITERATIONS_SMALL );
127  ENSURES( iterationCount < FAILSAFE_ITERATIONS_SMALL );
128 
129  /* Make sure that we don't inadvertently clear the sign bit if the
130  high bit of the value is clear */
131  if( !( buffer[ length - 1 ] & 0x80 ) )
132  buffer[ length++ ] = 0xFF;
133  }
134  ENSURES( length > 0 && length <= 8 );
135 
136  /* Output the value in reverse (big-endian) order */
137  sputc( stream, length );
138  for( i = length - 1; i > 0; i-- )
139  sputc( stream, buffer[ i ] );
140  return( sputc( stream, buffer[ 0 ] ) );
141  }
142 
143 /****************************************************************************
144 * *
145 * Sizeof Routines *
146 * *
147 ****************************************************************************/
148 
149 /* Determine the encoded size of an object given only a length. This is
150  implemented as a function rather than a macro since the macro form would
151  evaluate the length argument a great many times.
152 
153  The function checks for a length < 0 since this is frequently called as
154  part of a complex expression using the output of another function that
155  may return an error code. Because of this we don't use a REQUIRES()
156  predicate on it as we usually would but merely throw an exception in
157  debug mode */
158 
160 long sizeofObject( IN_LENGTH const long length )
161  {
162  REQUIRES( length < MAX_INTLENGTH );
163 
164  /* If we've been passed an error code as input, pass it back
165  unmodified */
166  if( length < 0 )
167  {
168  DEBUG_DIAG(( "Error code was passed to sizeof() function" ));
169  assert( DEBUG_WARN );
170  return( length );
171  }
172 
173  /* If we're about to exceed the maximum safe length range, don't try and
174  go any further */
175  if( length > MAX_INTLENGTH - 16 )
176  {
177  DEBUG_DIAG(( "Length exceeds maximum safe length value" ));
178  assert( DEBUG_WARN );
179  return( CRYPT_ERROR_OVERFLOW );
180  }
181 
182  return( sizeof( BYTE ) + calculateLengthSize( length ) + length );
183  }
184 
185 #ifdef USE_PKC
186 
187 /* Determine the size of a bignum. When we're writing these we can't use
188  sizeofObject() directly because the internal representation is unsigned
189  whereas the encoded form is signed */
190 
192 int signedBignumSize( IN TYPECAST( BIGNUM * ) const void *bignum )
193  {
194  assert( isReadPtr( bignum, sizeof( BIGNUM ) ) );
195 
196  return( BN_num_bytes( bignum ) + \
197  ( ( BN_high_bit( ( BIGNUM * ) bignum ) ) ? 1 : 0 ) );
198  }
199 #endif /* USE_PKC */
200 
201 /****************************************************************************
202 * *
203 * Write Routines for Primitive Objects *
204 * *
205 ****************************************************************************/
206 
207 /* Write a short/large/bignum integer value */
208 
209 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
210 int writeShortInteger( INOUT STREAM *stream, IN_INT const long integer,
211  IN_TAG const int tag )
212  {
213  assert( isWritePtr( stream, sizeof( STREAM ) ) );
214 
215  REQUIRES_S( integer >= 0 && integer < MAX_INTLENGTH );
216  REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
217 
218  writeTag( stream, ( tag == DEFAULT_TAG ) ? \
219  BER_INTEGER : MAKE_CTAG_PRIMITIVE( tag ) );
220  return( writeNumeric( stream, integer ) );
221  }
222 
224 int writeInteger( INOUT STREAM *stream,
225  IN_BUFFER( integerLength ) const BYTE *integer,
226  IN_LENGTH_SHORT const int integerLength,
227  IN_TAG const int tag )
228  {
229  const BOOLEAN leadingZero = ( integerLength > 0 && \
230  ( *integer & 0x80 ) ) ? 1 : 0;
231 
232  assert( isWritePtr( stream, sizeof( STREAM ) ) );
233  assert( isReadPtr( integer, integerLength ) );
234 
235  REQUIRES_S( integerLength >= 0 && integerLength < MAX_INTLENGTH_SHORT );
236  REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
237 
238  writeTag( stream, ( tag == DEFAULT_TAG ) ? \
239  BER_INTEGER : MAKE_CTAG_PRIMITIVE( tag ) );
240  writeLength( stream, integerLength + leadingZero );
241  if( leadingZero )
242  sputc( stream, 0 );
243  return( swrite( stream, integer, integerLength ) );
244  }
245 
246 #ifdef USE_PKC
247 
248 RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
249 int writeBignumTag( INOUT STREAM *stream,
250  IN TYPECAST( BIGNUM * ) const void *bignum,
251  IN_TAG const int tag )
252  {
253  BYTE buffer[ CRYPT_MAX_PKCSIZE + 8 ];
254  int length, status;
255 
256  assert( isWritePtr( stream, sizeof( STREAM ) ) );
257  assert( isReadPtr( bignum, sizeof( BIGNUM ) ) );
258 
259  REQUIRES_S( !BN_is_zero( ( BIGNUM * ) bignum ) );
260  REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
261 
262  /* If it's a dummy write, don't go through the full encoding process.
263  This optimisation both speeds things up and reduces unnecessary
264  writing of key data to memory */
265  if( sIsNullStream( stream ) )
266  return( sSkip( stream, sizeofBignum( bignum ) ) );
267 
268  status = exportBignum( buffer, CRYPT_MAX_PKCSIZE, &length, bignum );
269  if( cryptStatusError( status ) )
270  retIntError_Stream( stream );
271  status = writeInteger( stream, buffer, length, tag );
272  zeroise( buffer, CRYPT_MAX_PKCSIZE );
273  return( status );
274  }
275 #endif /* USE_PKC */
276 
277 /* Write an enumerated value */
278 
279 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
280 int writeEnumerated( INOUT STREAM *stream,
281  IN_RANGE( 0, 999 ) const int enumerated,
282  IN_TAG const int tag )
283  {
284  assert( isWritePtr( stream, sizeof( STREAM ) ) );
285 
286  REQUIRES_S( enumerated >= 0 && enumerated < 1000 );
287  REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
288 
289  writeTag( stream, ( tag == DEFAULT_TAG ) ? \
291  return( writeNumeric( stream, ( long ) enumerated ) );
292  }
293 
294 /* Write a null value */
295 
296 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
297 int writeNull( INOUT STREAM *stream, IN_TAG const int tag )
298  {
299  BYTE buffer[ 8 + 8 ];
300 
301  assert( isWritePtr( stream, sizeof( STREAM ) ) );
302 
303  REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
304 
305  buffer[ 0 ] = ( tag == DEFAULT_TAG ) ? \
306  BER_NULL : MAKE_CTAG_PRIMITIVE( tag );
307  buffer[ 1 ] = 0;
308  return( swrite( stream, buffer, 2 ) );
309  }
310 
311 /* Write a boolean value */
312 
313 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
314 int writeBoolean( INOUT STREAM *stream, const BOOLEAN boolean,
315  IN_TAG const int tag )
316  {
317  BYTE buffer[ 8 + 8 ];
318 
319  assert( isWritePtr( stream, sizeof( STREAM ) ) );
320 
321  REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
322 
323  buffer[ 0 ] = ( tag == DEFAULT_TAG ) ? \
325  buffer[ 1 ] = 1;
326  buffer[ 2 ] = boolean ? 0xFF : 0;
327  return( swrite( stream, buffer, 3 ) );
328  }
329 
330 /* Write an octet string */
331 
332 RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
333 int writeOctetString( INOUT STREAM *stream,
334  IN_BUFFER( length ) const BYTE *string,
335  IN_LENGTH_SHORT const int length,
336  IN_TAG const int tag )
337  {
338  assert( isWritePtr( stream, sizeof( STREAM ) ) );
339  assert( isReadPtr( string, length ) );
340 
341  REQUIRES_S( length > 0 && length < MAX_INTLENGTH_SHORT );
342  REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
343 
344  writeTag( stream, ( tag == DEFAULT_TAG ) ? \
346  writeLength( stream, length );
347  return( swrite( stream, string, length ) );
348  }
349 
350 /* Write a character string. This handles any of the myriad ASN.1 character
351  string types. The handling of the tag works somewhat differently here to
352  the usual manner in that since the function is polymorphic, the tag
353  defines the character string type and is always used (there's no
354  DEFAULT_TAG like the other functions use) */
355 
356 RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
357 int writeCharacterString( INOUT STREAM *stream,
358  IN_BUFFER( length ) const void *string,
359  IN_LENGTH_SHORT const int length,
360  IN_TAG_ENCODED const int tag )
361  {
362  assert( isWritePtr( stream, sizeof( STREAM ) ) );
363  assert( isReadPtr( string, length ) );
364 
365  REQUIRES_S( length > 0 && length < MAX_INTLENGTH_SHORT );
366  REQUIRES_S( ( tag >= BER_STRING_UTF8 && tag <= BER_STRING_BMP ) || \
367  ( tag >= MAKE_CTAG_PRIMITIVE( 0 ) && \
368  tag <= MAKE_CTAG_PRIMITIVE( MAX_CTAG_VALUE ) ) );
369 
370  writeTag( stream, tag );
371  writeLength( stream, length );
372  return( swrite( stream, string, length ) );
373  }
374 
375 /* Write a bit string */
376 
377 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
378 int writeBitString( INOUT STREAM *stream, IN_INT const int bitString,
379  IN_TAG const int tag )
380  {
381  BYTE buffer[ 16 + 8 ];
382  unsigned int value = 0;
383  int data = bitString, noBits = 0, i;
384 
385  assert( isWritePtr( stream, sizeof( STREAM ) ) );
386 
387  REQUIRES_S( bitString >= 0 && bitString < INT_MAX );
388  REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
389 
390  /* ASN.1 bitstrings start at bit 0, so we need to reverse the order of
391  the bits before we write them out */
392  for( i = 0; i < ( sizeof( int ) > 2 ? 32 : 16 ); i++ )
393  {
394  /* Update the number of significant bits */
395  if( data > 0 )
396  noBits++;
397 
398  /* Reverse the bits */
399  value <<= 1;
400  if( data & 1 )
401  value |= 1;
402  data >>= 1;
403  }
404 
405  /* Write the data as an ASN.1 BITSTRING. This has the potential to lose
406  some bits on 16-bit systems, but the only place where bit strings
407  longer than one or two bytes are used is with CMP's bizarre encoding
408  of error subcodes that just provide further information above and
409  beyond the main error code and text message, and it's unlikely that
410  too many people will be running a CMP server on a DOS box */
411  buffer[ 0 ] = ( tag == DEFAULT_TAG ) ? \
413  buffer[ 1 ] = 1 + ( ( noBits + 7 ) >> 3 );
414  buffer[ 2 ] = ~( ( noBits - 1 ) & 7 ) & 7;
415 #if UINT_MAX > 0xFFFF
416  buffer[ 3 ] = ( value >> 24 ) & 0xFF;
417  buffer[ 4 ] = ( value >> 16 ) & 0xFF;
418  buffer[ 5 ] = ( value >> 8 ) & 0xFF;
419  buffer[ 6 ] = value & 0xFF;
420 #else
421  buffer[ 3 ] = ( value >> 8 ) & 0xFF;
422  buffer[ 4 ] = value & 0xFF;
423 #endif /* 16 vs.32-bit systems */
424  return( swrite( stream, buffer, 3 + ( ( noBits + 7 ) >> 3 ) ) );
425  }
426 
427 /* Write a canonical UTCTime and GeneralizedTime value */
428 
430 static int writeTime( INOUT STREAM *stream, const time_t timeVal,
431  IN_TAG const int tag, const BOOLEAN isUTCTime )
432  {
433  struct tm timeInfo, *timeInfoPtr = &timeInfo;
434  char buffer[ 20 + 8 ];
435  const int length = isUTCTime ? 13 : 15;
436 
437  assert( isWritePtr( stream, sizeof( STREAM ) ) );
438 
439  REQUIRES_S( timeVal >= MIN_STORED_TIME_VALUE );
440  REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
441 
442  timeInfoPtr = gmTime_s( &timeVal, timeInfoPtr );
443  ENSURES_S( timeInfoPtr != NULL && timeInfoPtr->tm_year > 90 );
444  buffer[ 0 ] = ( tag != DEFAULT_TAG ) ? MAKE_CTAG_PRIMITIVE( tag ) : \
445  isUTCTime ? BER_TIME_UTC : BER_TIME_GENERALIZED;
446  buffer[ 1 ] = length;
447  if( isUTCTime )
448  {
449  sprintf_s( buffer + 2, 16, "%02d%02d%02d%02d%02d%02dZ",
450  timeInfoPtr->tm_year % 100, timeInfoPtr->tm_mon + 1,
451  timeInfoPtr->tm_mday, timeInfoPtr->tm_hour,
452  timeInfoPtr->tm_min, timeInfoPtr->tm_sec );
453  }
454  else
455  {
456  sprintf_s( buffer + 2, 16, "%04d%02d%02d%02d%02d%02dZ",
457  timeInfoPtr->tm_year + 1900, timeInfoPtr->tm_mon + 1,
458  timeInfoPtr->tm_mday, timeInfoPtr->tm_hour,
459  timeInfoPtr->tm_min, timeInfoPtr->tm_sec );
460  }
461  return( swrite( stream, buffer, length + 2 ) );
462  }
463 
464 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
465 int writeUTCTime( INOUT STREAM *stream, const time_t timeVal,
466  IN_TAG const int tag )
467  {
468  assert( isWritePtr( stream, sizeof( STREAM ) ) );
469 
470  REQUIRES_S( timeVal >= MIN_STORED_TIME_VALUE );
471  REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
472 
473  return( writeTime( stream, timeVal, tag, TRUE ) );
474  }
475 
476 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
477 int writeGeneralizedTime( INOUT STREAM *stream, const time_t timeVal,
478  IN_TAG const int tag )
479  {
480  assert( isWritePtr( stream, sizeof( STREAM ) ) );
481 
482  REQUIRES_S( timeVal >= MIN_STORED_TIME_VALUE );
483  REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
484 
485  return( writeTime( stream, timeVal, tag, FALSE) );
486  }
487 
488 /****************************************************************************
489 * *
490 * Write Routines for Constructed Objects *
491 * *
492 ****************************************************************************/
493 
494 /* Write the start of an encapsulating SEQUENCE, SET, or generic tagged
495  constructed object. The difference between writeOctet/BitStringHole() and
496  writeGenericHole() is that the octet/bit-string versions create a normal
497  or context-specific-tagged primitive string while the generic version
498  creates a pure hole with no processing of tags */
499 
500 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
501 int writeSequence( INOUT STREAM *stream, IN_LENGTH_Z const int length )
502  {
503  assert( isWritePtr( stream, sizeof( STREAM ) ) );
504 
505  REQUIRES_S( length >= 0 && length < MAX_INTLENGTH );
506 
507  writeTag( stream, BER_SEQUENCE );
508  return( writeLength( stream, length ) );
509  }
510 
511 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
512 int writeSet( INOUT STREAM *stream, IN_LENGTH_Z const int length )
513  {
514  assert( isWritePtr( stream, sizeof( STREAM ) ) );
515 
516  REQUIRES_S( length >= 0 && length < MAX_INTLENGTH );
517 
518  writeTag( stream, BER_SET );
519  return( writeLength( stream, length ) );
520  }
521 
522 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
523 int writeConstructed( INOUT STREAM *stream, IN_LENGTH_Z const int length,
524  IN_TAG const int tag )
525  {
526  assert( isWritePtr( stream, sizeof( STREAM ) ) );
527 
528  REQUIRES_S( length >= 0 && length < MAX_INTLENGTH );
529  REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
530 
531  writeTag( stream, ( tag == DEFAULT_TAG ) ? \
532  BER_SEQUENCE : MAKE_CTAG( tag ) );
533  return( writeLength( stream, length ) );
534  }
535 
536 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
537 int writeOctetStringHole( INOUT STREAM *stream,
538  IN_LENGTH_Z const int length,
539  IN_TAG const int tag )
540  {
541  assert( isWritePtr( stream, sizeof( STREAM ) ) );
542 
543  REQUIRES_S( length >= 0 && length < MAX_INTLENGTH );
544  REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
545 
546  writeTag( stream, ( tag == DEFAULT_TAG ) ? \
548  return( writeLength( stream, length ) );
549  }
550 
551 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
552 int writeBitStringHole( INOUT STREAM *stream, IN_LENGTH_Z const int length,
553  IN_TAG const int tag )
554  {
555  assert( isWritePtr( stream, sizeof( STREAM ) ) );
556 
557  REQUIRES_S( length >= 0 && length < MAX_INTLENGTH );
558  REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
559 
560  writeTag( stream, ( tag == DEFAULT_TAG ) ? \
562  writeLength( stream, length + 1 ); /* +1 for bit count */
563  return( sputc( stream, 0 ) );
564  }
565 
566 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
567 int writeGenericHole( INOUT STREAM *stream, IN_LENGTH_Z const int length,
568  IN_TAG const int tag )
569  {
570  assert( isWritePtr( stream, sizeof( STREAM ) ) );
571 
572  REQUIRES_S( length >= 0 && length < MAX_INTLENGTH );
573  REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
574 
575  writeTag( stream, tag );
576  return( writeLength( stream, length ) );
577  }