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