1 /****************************************************************************
2 *																			*
3 *							Certificate Write Routines						*
4 *						Copyright Peter Gutmann 1996-2012					*
5 *																			*
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9   #include "cert.h"
10   #include "asn1_ext.h"
11 #else
12   #include "cert/cert.h"
13   #include "enc_dec/asn1_ext.h"
14 #endif /* Compiler-specific includes */
15 
16 /* The X.509 version numbers */
17 
18 enum { X509VERSION_1, X509VERSION_2, X509VERSION_3 };
19 enum { X509ACVERSION_1, X509ACVERSION_2 };
20 
21 #ifdef USE_CERTIFICATES
22 
23 /****************************************************************************
24 *																			*
25 *								Utility Functions							*
26 *																			*
27 ****************************************************************************/
28 
29 #if defined( USE_CERTREV ) || defined( USE_CERTVAL )
30 
31 /* Set/refresh a nonce in an RTCS/OCSP request (difficile est tenere quae
32    acceperis nisi exerceas) */
33 
setNonce(INOUT ATTRIBUTE_PTR ** attributePtrPtr,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE nonceType)34 static int setNonce( INOUT ATTRIBUTE_PTR **attributePtrPtr,
35 					 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE nonceType )
36 	{
37 	ATTRIBUTE_PTR *attributePtr;
38 	MESSAGE_DATA msgData;
39 	void *noncePtr;
40 	int nonceLength, status;
41 
42 	assert( isWritePtr( attributePtrPtr, sizeof( ATTRIBUTE_PTR * ) ) );
43 
44 	REQUIRES( nonceType == CRYPT_CERTINFO_CMS_NONCE || \
45 			  nonceType == CRYPT_CERTINFO_OCSP_NONCE );
46 
47 	/* To ensure freshness we always use a new nonce when we write an RTCS
48 	   or OCSP request */
49 	attributePtr = findAttributeField( *attributePtrPtr, nonceType,
50 									   CRYPT_ATTRIBUTE_NONE );
51 	if( attributePtr == NULL )
52 		{
53 		CRYPT_ATTRIBUTE_TYPE dummy1;
54 		CRYPT_ERRTYPE_TYPE dummy2;
55 		BYTE nonce[ CRYPT_MAX_HASHSIZE + 8 ];
56 
57 		/* There's no nonce present, add a new one */
58 		setMessageData( &msgData, nonce, 16 );
59 		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
60 								  IMESSAGE_GETATTRIBUTE_S, &msgData,
61 								  CRYPT_IATTRIBUTE_RANDOM_NONCE );
62 		if( cryptStatusError( status ) )
63 			return( status );
64 		return( addAttributeFieldString( attributePtrPtr, nonceType,
65 										 CRYPT_ATTRIBUTE_NONE, nonce, 16, 0,
66 										 &dummy1, &dummy2 ) );
67 		}
68 
69 	/* There's an existing nonce present, refresh it */
70 	status = getAttributeDataPtr( attributePtr, &noncePtr, &nonceLength );
71 	if( cryptStatusError( status ) )
72 		return( status );
73 	ENSURES( nonceLength == 16 );
74 	setMessageData( &msgData, noncePtr, 16 );
75 	return( krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
76 							 &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE ) );
77 	}
78 #endif /* USE_CERTREV || USE_CERTVAL */
79 
80 /****************************************************************************
81 *																			*
82 *							Write Certificate Objects						*
83 *																			*
84 ****************************************************************************/
85 
86 /* Write certificate information:
87 
88 	CertificateInfo ::= SEQUENCE {
89 		version			  [ 0 ]	EXPLICIT INTEGER DEFAULT(0),
90 		serialNumber			INTEGER,
91 		signature				AlgorithmIdentifier,
92 		issuer					Name
93 		validity				Validity,
94 		subject					Name,
95 		subjectPublicKeyInfo	SubjectPublicKeyInfo,
96 		extensions		  [ 3 ]	Extensions OPTIONAL
97 		} */
98 
99 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
writeCertInfo(INOUT STREAM * stream,INOUT CERT_INFO * subjectCertInfoPtr,const CERT_INFO * issuerCertInfoPtr,IN_HANDLE const CRYPT_CONTEXT iIssuerCryptContext)100 static int writeCertInfo( INOUT STREAM *stream,
101 						  INOUT CERT_INFO *subjectCertInfoPtr,
102 						  const CERT_INFO *issuerCertInfoPtr,
103 						  IN_HANDLE const CRYPT_CONTEXT iIssuerCryptContext )
104 	{
105 	const CERT_CERT_INFO *certCertInfo = subjectCertInfoPtr->cCertCert;
106 	int algoIdInfoSize, length, extensionSize, status;
107 
108 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
109 	assert( isWritePtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
110 	assert( isReadPtr( issuerCertInfoPtr, sizeof( CERT_INFO ) ) );
111 
112 	REQUIRES( isHandleRangeValid( iIssuerCryptContext ) );
113 
114 	/* Perform any necessary pre-encoding steps */
115 	if( sIsNullStream( stream ) )
116 		{
117 		int isXyzzyCert, dnCheckFlag = PRE_CHECK_DN;
118 
119 		/* If it's a XYZZY certificate then a complete DN isn't required */
120 		status = getCertComponent( subjectCertInfoPtr, CRYPT_CERTINFO_XYZZY,
121 								   &isXyzzyCert );
122 		if( cryptStatusOK( status ) && isXyzzyCert )
123 			dnCheckFlag = PRE_CHECK_DN_PARTIAL;
124 
125 		status = preEncodeCertificate( subjectCertInfoPtr, issuerCertInfoPtr,
126 									   PRE_SET_STANDARDATTR | PRE_SET_ISSUERATTR | \
127 									   PRE_SET_ISSUERDN | PRE_SET_VALIDITYPERIOD );
128 		if( cryptStatusError( status ) )
129 			return( status );
130 		status = preCheckCertificate( subjectCertInfoPtr, issuerCertInfoPtr,
131 									  PRE_CHECK_SPKI | dnCheckFlag | \
132 									  PRE_CHECK_ISSUERDN | PRE_CHECK_SERIALNO | \
133 						( ( subjectCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) ? \
134 									  0 : PRE_CHECK_NONSELFSIGNED_DN ),
135 						( issuerCertInfoPtr->subjectDNptr != NULL ) ? \
136 									  PRE_FLAG_DN_IN_ISSUERCERT : \
137 									  PRE_FLAG_NONE );
138 		if( cryptStatusError( status ) )
139 			return( status );
140 		}
141 
142 	/* Determine how the issuer name will be encoded */
143 	status = length = ( issuerCertInfoPtr->subjectDNptr != NULL ) ? \
144 						issuerCertInfoPtr->subjectDNsize : \
145 						sizeofDN( subjectCertInfoPtr->issuerName );
146 	if( cryptStatusError( status ) )
147 		return( status );
148 	subjectCertInfoPtr->issuerDNsize = length;
149 	status = length = sizeofDN( subjectCertInfoPtr->subjectName );
150 	if( cryptStatusError( status ) )
151 		return( status );
152 	subjectCertInfoPtr->subjectDNsize = length;
153 
154 	/* Determine the size of the certificate information */
155 	algoIdInfoSize = sizeofContextAlgoID( iIssuerCryptContext,
156 										  certCertInfo->hashAlgo );
157 	if( cryptStatusError( algoIdInfoSize ) )
158 		return( algoIdInfoSize  );
159 	extensionSize = sizeofAttributes( subjectCertInfoPtr->attributes,
160 									  CRYPT_CERTTYPE_CERTIFICATE );
161 	if( cryptStatusError( extensionSize ) )
162 		return( extensionSize );
163 	length = sizeofInteger( certCertInfo->serialNumber,
164 							certCertInfo->serialNumberLength ) + \
165 			 algoIdInfoSize + \
166 			 subjectCertInfoPtr->issuerDNsize + \
167 			 sizeofObject( sizeofUTCTime() * 2 ) + \
168 			 subjectCertInfoPtr->subjectDNsize + \
169 			 subjectCertInfoPtr->publicKeyInfoSize;
170 	if( extensionSize > 0 )
171 		{
172 		length += sizeofObject( sizeofShortInteger( X509VERSION_3 ) ) + \
173 				  sizeofObject( sizeofObject( extensionSize ) );
174 		}
175 
176 	/* Write the outer SEQUENCE wrapper */
177 	writeSequence( stream, length );
178 
179 	/* If there are extensions present, mark this as a v3 certificate */
180 	if( extensionSize > 0 )
181 		{
182 		writeConstructed( stream, sizeofShortInteger( X509VERSION_3 ),
183 						  CTAG_CE_VERSION );
184 		writeShortInteger( stream, X509VERSION_3, DEFAULT_TAG );
185 		}
186 
187 	/* Write the serial number and signature algorithm identifier */
188 	writeInteger( stream, certCertInfo->serialNumber,
189 				  certCertInfo->serialNumberLength, DEFAULT_TAG );
190 	status = writeContextAlgoID( stream, iIssuerCryptContext,
191 								 certCertInfo->hashAlgo );
192 	if( cryptStatusError( status ) )
193 		return( status );
194 
195 	/* Write the issuer name, validity period, subject name, and public key
196 	   information */
197 	if( issuerCertInfoPtr->subjectDNptr != NULL )
198 		status = swrite( stream, issuerCertInfoPtr->subjectDNptr,
199 						 issuerCertInfoPtr->subjectDNsize );
200 	else
201 		status = writeDN( stream, subjectCertInfoPtr->issuerName, DEFAULT_TAG );
202 	if( cryptStatusError( status ) )
203 		return( status );
204 	writeSequence( stream, sizeofUTCTime() * 2 );
205 	writeUTCTime( stream, subjectCertInfoPtr->startTime, DEFAULT_TAG );
206 	writeUTCTime( stream, subjectCertInfoPtr->endTime, DEFAULT_TAG );
207 	status = writeDN( stream, subjectCertInfoPtr->subjectName, DEFAULT_TAG );
208 	if( cryptStatusOK( status ) )
209 		status = swrite( stream, subjectCertInfoPtr->publicKeyInfo,
210 						 subjectCertInfoPtr->publicKeyInfoSize );
211 	if( cryptStatusError( status ) || extensionSize <= 0 )
212 		return( status );
213 
214 	/* Write the extensions */
215 	return( writeAttributes( stream, subjectCertInfoPtr->attributes,
216 							 CRYPT_CERTTYPE_CERTIFICATE, extensionSize ) );
217 	}
218 
219 /* Write attribute certificate information.  There are two variants of this,
220    v1 attributes certificates that were pretty much never used (the fact
221    that no-one had bothered to define any attributes to be used with them
222    didn't help here) and v2 attribute certificates that are also almost
223    never used but are newer, we write v2 certificates.  The original v1
224    attribute certificate format was:
225 
226 	AttributeCertificateInfo ::= SEQUENCE {
227 		version					INTEGER DEFAULT(0),
228 		owner			  [ 1 ]	Name,
229 		issuer					Name,
230 		signature				AlgorithmIdentifier,
231 		serialNumber			INTEGER,
232 		validity				Validity,
233 		attributes				SEQUENCE OF Attribute,
234 		extensions				Extensions OPTIONAL
235 		}
236 
237    In v2 this changed to:
238 
239 	AttributeCertificateInfo ::= SEQUENCE {
240 		version					INTEGER (1),
241 		holder					SEQUENCE {
242 			entityNames	  [ 1 ]	SEQUENCE OF {
243 				entityName[ 4 ]	EXPLICIT Name
244 								},
245 							}
246 		issuer			  [ 0 ]	SEQUENCE {
247 			issuerNames			SEQUENCE OF {
248 				issuerName[ 4 ]	EXPLICIT Name
249 								},
250 							}
251 		signature				AlgorithmIdentifier,
252 		serialNumber			INTEGER,
253 		validity				SEQUENCE {
254 			notBefore			GeneralizedTime,
255 			notAfter			GeneralizedTime
256 								},
257 		attributes				SEQUENCE OF Attribute,
258 		extensions				Extensions OPTIONAL
259 		}
260 
261    In order to write the issuer and owner/holder DN as GeneralName we encode
262    it using the DN choice of a GeneralName with explicit tag 4, see the
263    comments on GeneralName encoding in ext_def.c for an explanation of the
264    tagging */
265 
266 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
writeAttributeCertInfo(INOUT STREAM * stream,INOUT CERT_INFO * subjectCertInfoPtr,const CERT_INFO * issuerCertInfoPtr,IN_HANDLE const CRYPT_CONTEXT iIssuerCryptContext)267 static int writeAttributeCertInfo( INOUT STREAM *stream,
268 								   INOUT CERT_INFO *subjectCertInfoPtr,
269 								   const CERT_INFO *issuerCertInfoPtr,
270 								   IN_HANDLE const CRYPT_CONTEXT iIssuerCryptContext )
271 	{
272 	const CERT_CERT_INFO *certCertInfo = subjectCertInfoPtr->cCertCert;
273 	int algoIdInfoSize, length, extensionSize;
274 	int issuerNameSize, holderNameSize, status;
275 
276 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
277 	assert( isWritePtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
278 	assert( isReadPtr( issuerCertInfoPtr, sizeof( CERT_INFO ) ) );
279 
280 	REQUIRES( isHandleRangeValid( iIssuerCryptContext ) );
281 
282 	/* Perform any necessary pre-encoding steps */
283 	if( sIsNullStream( stream ) )
284 		{
285 		status = preEncodeCertificate( subjectCertInfoPtr, issuerCertInfoPtr,
286 									   PRE_SET_ISSUERDN | PRE_SET_ISSUERATTR | \
287 									   PRE_SET_VALIDITYPERIOD );
288 		if( cryptStatusError( status ) )
289 			return( status );
290 		status = preCheckCertificate( subjectCertInfoPtr, issuerCertInfoPtr,
291 									  PRE_CHECK_DN | PRE_CHECK_ISSUERDN | \
292 									  PRE_CHECK_SERIALNO | \
293 						( ( subjectCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) ? \
294 									  0 : PRE_CHECK_NONSELFSIGNED_DN ),
295 						( issuerCertInfoPtr->subjectDNptr != NULL ) ? \
296 									  PRE_FLAG_DN_IN_ISSUERCERT : \
297 									  PRE_FLAG_NONE );
298 		if( cryptStatusError( status ) )
299 			return( status );
300 		}
301 
302 	/* Determine how the issuer name will be encoded */
303 	status = length = ( issuerCertInfoPtr->subjectDNptr != NULL ) ? \
304 						issuerCertInfoPtr->subjectDNsize : \
305 						sizeofDN( subjectCertInfoPtr->issuerName );
306 	if( cryptStatusError( status ) )
307 		return( status );
308  	issuerNameSize = length;
309 	status = length = sizeofDN( subjectCertInfoPtr->subjectName );
310 	if( cryptStatusError( status ) )
311 		return( status );
312 	holderNameSize = length;
313 
314 	/* Determine the size of the certificate information */
315 	algoIdInfoSize = sizeofContextAlgoID( iIssuerCryptContext,
316 										  certCertInfo->hashAlgo );
317 	if( cryptStatusError( algoIdInfoSize ) )
318 		return( algoIdInfoSize  );
319 	extensionSize = sizeofAttributes( subjectCertInfoPtr->attributes,
320 									  CRYPT_CERTTYPE_ATTRIBUTE_CERT );
321 	if( cryptStatusError( extensionSize ) )
322 		return( extensionSize );
323 	length = sizeofShortInteger( X509ACVERSION_2 ) + \
324 			 sizeofObject( sizeofObject( sizeofObject( holderNameSize ) ) ) + \
325 			 sizeofObject( sizeofObject( sizeofObject( issuerNameSize ) ) ) + \
326 			 algoIdInfoSize + \
327 			 sizeofInteger( certCertInfo->serialNumber,
328 							certCertInfo->serialNumberLength ) + \
329 			 sizeofObject( sizeofGeneralizedTime() * 2 ) + \
330 			 sizeofObject( 0 );
331 	if( extensionSize > 0 )
332 		length += ( int ) sizeofObject( extensionSize );
333 
334 	/* Write the outer SEQUENCE wrapper and version */
335 	writeSequence( stream, length );
336 	writeShortInteger( stream, X509ACVERSION_2, DEFAULT_TAG );
337 
338 	/* Write the owner and issuer name */
339 	writeSequence( stream, sizeofObject( sizeofObject( holderNameSize ) ) );
340 	writeConstructed( stream, sizeofObject( holderNameSize ),
341 					  CTAG_AC_HOLDER_ENTITYNAME );
342 	writeConstructed( stream, holderNameSize, 4 );
343 	status = writeDN( stream, subjectCertInfoPtr->subjectName, DEFAULT_TAG );
344 	if( cryptStatusOK( status ) )
345 		{
346 		writeConstructed( stream,
347 						  sizeofObject( sizeofObject( issuerNameSize ) ), 0 );
348 		writeSequence( stream, sizeofObject( issuerNameSize ) );
349 		writeConstructed( stream, issuerNameSize, 4 );
350 		if( issuerCertInfoPtr->subjectDNptr != NULL )
351 			status = swrite( stream, issuerCertInfoPtr->subjectDNptr,
352 							 issuerCertInfoPtr->subjectDNsize );
353 		else
354 			status = writeDN( stream, subjectCertInfoPtr->issuerName, DEFAULT_TAG );
355 		}
356 	if( cryptStatusError( status ) )
357 		return( status );
358 
359 	/* Write the signature algorithm identifier, serial number and validity
360 	   period */
361 	writeContextAlgoID( stream, iIssuerCryptContext, certCertInfo->hashAlgo );
362 	writeInteger( stream, certCertInfo->serialNumber,
363 				  certCertInfo->serialNumberLength, DEFAULT_TAG );
364 	writeSequence( stream, sizeofGeneralizedTime() * 2 );
365 	writeGeneralizedTime( stream, subjectCertInfoPtr->startTime,
366 						  DEFAULT_TAG );
367 	status = writeGeneralizedTime( stream, subjectCertInfoPtr->endTime,
368 								   DEFAULT_TAG );
369 	if( cryptStatusError( status ) )
370 		return( status );
371 
372 	/* Write the attributes */
373 	status = writeSequence( stream, 0 );
374 	if( cryptStatusError( status ) || extensionSize <= 0 )
375 		return( status );
376 
377 	/* Write the extensions */
378 	return( writeAttributes( stream, subjectCertInfoPtr->attributes,
379 							 CRYPT_CERTTYPE_ATTRIBUTE_CERT, extensionSize ) );
380 	}
381 
382 /****************************************************************************
383 *																			*
384 *								Write CRL Objects							*
385 *																			*
386 ****************************************************************************/
387 
388 #ifdef USE_CERTREV
389 
390 /* Write CRL information:
391 
392 	CRLInfo ::= SEQUENCE {
393 		version					INTEGER DEFAULT(0),
394 		signature				AlgorithmIdentifier,
395 		issuer					Name,
396 		thisUpdate				UTCTime,
397 		nextUpdate				UTCTime OPTIONAL,
398 		revokedCertificates		SEQUENCE OF RevokedCerts,
399 		extensions		  [ 0 ]	Extensions OPTIONAL
400 		} */
401 
402 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
writeCRLInfo(INOUT STREAM * stream,INOUT CERT_INFO * subjectCertInfoPtr,IN_OPT const CERT_INFO * issuerCertInfoPtr,IN_HANDLE_OPT const CRYPT_CONTEXT iIssuerCryptContext)403 static int writeCRLInfo( INOUT STREAM *stream,
404 						 INOUT CERT_INFO *subjectCertInfoPtr,
405 						 IN_OPT const CERT_INFO *issuerCertInfoPtr,
406 						 IN_HANDLE_OPT const CRYPT_CONTEXT iIssuerCryptContext )
407 	{
408 	const CERT_REV_INFO *certRevInfo = subjectCertInfoPtr->cCertRev;
409 	REVOCATION_INFO *revocationInfo;
410 	const BOOLEAN isCrlEntry = ( issuerCertInfoPtr == NULL ) ? TRUE : FALSE;
411 	int length, algoIdInfoSize, extensionSize, revocationInfoLength = 0;
412 	int iterationCount, status;
413 
414 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
415 	assert( isWritePtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
416 	assert( ( issuerCertInfoPtr == NULL && \
417 			  iIssuerCryptContext == CRYPT_UNUSED ) || \
418 			( isReadPtr( issuerCertInfoPtr, sizeof( CERT_INFO ) ) && \
419 			  isHandleRangeValid( iIssuerCryptContext ) ) );
420 
421 	REQUIRES( ( issuerCertInfoPtr == NULL && \
422 				iIssuerCryptContext == CRYPT_UNUSED ) || \
423 			  ( issuerCertInfoPtr != NULL && \
424 				isHandleRangeValid( iIssuerCryptContext ) ) );
425 
426 	/* Perform any necessary pre-encoding steps */
427 	if( sIsNullStream( stream ) )
428 		{
429 		if( isCrlEntry )
430 			{
431 			status = preEncodeCertificate( subjectCertInfoPtr, NULL,
432 										   PRE_SET_REVINFO );
433 			}
434 		else
435 			{
436 			status = preEncodeCertificate( subjectCertInfoPtr,
437 										   issuerCertInfoPtr,
438 										   PRE_SET_ISSUERDN | \
439 										   PRE_SET_ISSUERATTR | \
440 										   PRE_SET_REVINFO );
441 			if( cryptStatusError( status ) )
442 				return( status );
443 			status = preCheckCertificate( subjectCertInfoPtr,
444 										  issuerCertInfoPtr,
445 										  PRE_CHECK_ISSUERCERTDN | \
446 										  PRE_CHECK_ISSUERDN,
447 										  PRE_FLAG_DN_IN_ISSUERCERT );
448 			}
449 		if( cryptStatusError( status ) )
450 			return( status );
451 		}
452 
453 	/* Process CRL entries and version information */
454 	subjectCertInfoPtr->version = \
455 					( subjectCertInfoPtr->attributes != NULL ) ? 2 : 1;
456 	for( revocationInfo = certRevInfo->revocations, iterationCount = 0;
457 		 revocationInfo != NULL && iterationCount < FAILSAFE_ITERATIONS_MAX;
458 		 revocationInfo = revocationInfo->next, iterationCount++ )
459 		{
460 		const int crlEntrySize = sizeofCRLentry( revocationInfo );
461 
462 		if( cryptStatusError( crlEntrySize ) )
463 			return( crlEntrySize );
464 		revocationInfoLength += crlEntrySize;
465 
466 		/* If there are per-entry extensions present it's a v2 CRL */
467 		if( revocationInfo->attributes != NULL )
468 			subjectCertInfoPtr->version = 2;
469 		}
470 	ENSURES( iterationCount < FAILSAFE_ITERATIONS_MAX );
471 
472 	/* If we're being asked to write a single CRL entry, we don't try and go
473 	   any further since the remaining CRL fields (and issuer information)
474 	   may not be set up */
475 	if( isCrlEntry )
476 		return( writeCRLentry( stream, certRevInfo->currentRevocation ) );
477 
478 	/* Determine how big the encoded CRL will be */
479 	algoIdInfoSize = sizeofContextAlgoID( iIssuerCryptContext,
480 										  certRevInfo->hashAlgo );
481 	if( cryptStatusError( algoIdInfoSize ) )
482 		return( algoIdInfoSize  );
483 	extensionSize = sizeofAttributes( subjectCertInfoPtr->attributes,
484 									  CRYPT_CERTTYPE_CRL );
485 	if( cryptStatusError( extensionSize ) )
486 		return( extensionSize );
487 	length = algoIdInfoSize + \
488 			 issuerCertInfoPtr->subjectDNsize + \
489 			 sizeofUTCTime() + \
490 			 ( ( subjectCertInfoPtr->endTime > MIN_TIME_VALUE ) ? \
491 				sizeofUTCTime() : 0 ) + \
492 			 sizeofObject( revocationInfoLength );
493 	if( extensionSize > 0 )
494 		{
495 		length += sizeofShortInteger( X509VERSION_2 ) + \
496 			 	  sizeofObject( sizeofObject( extensionSize ) );
497 		}
498 
499 	/* Write the outer SEQUENCE wrapper */
500 	writeSequence( stream, length );
501 
502 	/* If there are extensions present, mark this as a v2 CRL */
503 	if( extensionSize > 0 )
504 		writeShortInteger( stream, X509VERSION_2, DEFAULT_TAG );
505 
506 	/* Write the signature algorithm identifier, issuer name, and CRL time */
507 	status = writeContextAlgoID( stream, iIssuerCryptContext,
508 								 certRevInfo->hashAlgo );
509 	if( cryptStatusError( status ) )
510 		return( status );
511 	swrite( stream, issuerCertInfoPtr->subjectDNptr,
512 			issuerCertInfoPtr->subjectDNsize );
513 	status = writeUTCTime( stream, subjectCertInfoPtr->startTime,
514 						   DEFAULT_TAG );
515 	if( subjectCertInfoPtr->endTime > MIN_TIME_VALUE )
516 		status = writeUTCTime( stream, subjectCertInfoPtr->endTime,
517 							   DEFAULT_TAG );
518 	if( cryptStatusError( status ) )
519 		return( status );
520 
521 	/* Write the SEQUENCE OF revoked certificates wrapper and the revoked
522 	   certificate information */
523 	status = writeSequence( stream, revocationInfoLength );
524 	for( revocationInfo = certRevInfo->revocations, iterationCount = 0;
525 		 cryptStatusOK( status ) && revocationInfo != NULL && \
526 			 iterationCount < FAILSAFE_ITERATIONS_MAX;
527 		 revocationInfo = revocationInfo->next, iterationCount++ )
528 		{
529 		status = writeCRLentry( stream, revocationInfo );
530 		}
531 	ENSURES( iterationCount < FAILSAFE_ITERATIONS_MAX );
532 	if( cryptStatusError( status ) || extensionSize <= 0 )
533 		return( status );
534 	ANALYSER_HINT( subjectCertInfoPtr->attributes != NULL );
535 
536 	/* Write the extensions */
537 	return( writeAttributes( stream, subjectCertInfoPtr->attributes,
538 							 CRYPT_CERTTYPE_CRL, extensionSize ) );
539 	}
540 #endif /* USE_CERTREV */
541 
542 /****************************************************************************
543 *																			*
544 *						Write Certificate Request Objects					*
545 *																			*
546 ****************************************************************************/
547 
548 #ifdef USE_CERTREQ
549 
550 /* Write certificate request information:
551 
552 	CertificationRequestInfo ::= SEQUENCE {
553 		version					INTEGER (0),
554 		subject					Name,
555 		subjectPublicKeyInfo	SubjectPublicKeyInfo,
556 		attributes		  [ 0 ]	SET OF Attribute
557 		}
558 
559    If extensions are present they are encoded as:
560 
561 	SEQUENCE {							-- Attribute from X.501
562 		OBJECT IDENTIFIER {pkcs-9 14},	--   type
563 		SET OF {						--   values
564 			SEQUENCE OF {				-- ExtensionReq from CMMF draft
565 				<X.509v3 extensions>
566 				}
567 			}
568 		} */
569 
570 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
writeCertRequestInfo(INOUT STREAM * stream,INOUT CERT_INFO * subjectCertInfoPtr,STDC_UNUSED const CERT_INFO * issuerCertInfoPtr,IN_HANDLE const CRYPT_CONTEXT iIssuerCryptContext)571 static int writeCertRequestInfo( INOUT STREAM *stream,
572 								 INOUT CERT_INFO *subjectCertInfoPtr,
573 								 STDC_UNUSED const CERT_INFO *issuerCertInfoPtr,
574 								 IN_HANDLE const CRYPT_CONTEXT iIssuerCryptContext )
575 	{
576 	int length, extensionSize, status;
577 
578 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
579 	assert( isWritePtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
580 
581 	REQUIRES( issuerCertInfoPtr == NULL );
582 	REQUIRES( isHandleRangeValid( iIssuerCryptContext ) );/* Not used here */
583 
584 	/* Make sure that everything is in order */
585 	if( sIsNullStream( stream ) )
586 		{
587 		status = preCheckCertificate( subjectCertInfoPtr, NULL,
588 									  PRE_CHECK_SPKI | PRE_CHECK_DN_PARTIAL,
589 									  PRE_FLAG_NONE );
590 		if( cryptStatusError( status ) )
591 			return( status );
592 		}
593 
594 	/* Determine how big the encoded certificate request will be */
595 	status = length = sizeofDN( subjectCertInfoPtr->subjectName );
596 	if( cryptStatusError( status ) )
597 		return( status );
598 	subjectCertInfoPtr->subjectDNsize = length;
599 	extensionSize = sizeofAttributes( subjectCertInfoPtr->attributes,
600 									  CRYPT_CERTTYPE_CERTREQUEST );
601 	if( cryptStatusError( extensionSize ) )
602 		return( extensionSize );
603 	length = sizeofShortInteger( 0 ) + \
604 			 subjectCertInfoPtr->subjectDNsize + \
605 			 subjectCertInfoPtr->publicKeyInfoSize;
606 	length += ( int ) sizeofObject( \
607 							( extensionSize > 0 ) ? extensionSize : 0 );
608 
609 	/* Write the header, version number, DN, and public key information */
610 	writeSequence( stream, length );
611 	writeShortInteger( stream, 0, DEFAULT_TAG );
612 	status = writeDN( stream, subjectCertInfoPtr->subjectName, DEFAULT_TAG );
613 	if( cryptStatusOK( status ) )
614 		status = swrite( stream, subjectCertInfoPtr->publicKeyInfo,
615 						 subjectCertInfoPtr->publicKeyInfoSize );
616 	if( cryptStatusError( status ) )
617 		return( status );
618 
619 	/* Write the attributes.  If there are no attributes we still have to
620 	   write an (erroneous) zero-length field */
621 	if( extensionSize <= 0 )
622 		return( writeConstructed( stream, 0, CTAG_CR_ATTRIBUTES ) );
623 	return( writeAttributes( stream, subjectCertInfoPtr->attributes,
624 							 CRYPT_CERTTYPE_CERTREQUEST, extensionSize ) );
625 	}
626 
627 /* Write CRMF certificate request information:
628 
629 	CertReq ::= SEQUENCE {
630 		certReqID				INTEGER (0),
631 		certTemplate			SEQUENCE {
632 			validity	  [ 4 ]	SEQUENCE {
633 				validFrom [ 0 ]	EXPLICIT GeneralizedTime OPTIONAL,
634 				validTo	  [ 1 ] EXPLICIT GeneralizedTime OPTIONAL
635 				} OPTIONAL,
636 			subject		  [ 5 ]	EXPLICIT Name OPTIONAL,
637 			publicKey	  [ 6 ]	SubjectPublicKeyInfo,
638 			extensions	  [ 9 ]	SET OF Attribute OPTIONAL
639 			}
640 		} */
641 
642 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
writeCrmfRequestInfo(INOUT STREAM * stream,INOUT CERT_INFO * subjectCertInfoPtr,STDC_UNUSED const CERT_INFO * issuerCertInfoPtr,IN_HANDLE const CRYPT_CONTEXT iIssuerCryptContext)643 static int writeCrmfRequestInfo( INOUT STREAM *stream,
644 								 INOUT CERT_INFO *subjectCertInfoPtr,
645 								 STDC_UNUSED const CERT_INFO *issuerCertInfoPtr,
646 								 IN_HANDLE const CRYPT_CONTEXT iIssuerCryptContext )
647 	{
648 	int payloadLength, extensionSize, subjectDNsize = 0, timeSize = 0;
649 	int status = CRYPT_OK;
650 
651 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
652 	assert( isWritePtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
653 
654 	REQUIRES( issuerCertInfoPtr == NULL );
655 	REQUIRES( isHandleRangeValid( iIssuerCryptContext ) );/* Not used here */
656 
657 	/* Make sure that everything is in order */
658 	if( sIsNullStream( stream ) )
659 		{
660 		status = preCheckCertificate( subjectCertInfoPtr, NULL,
661 									  PRE_CHECK_SPKI | \
662 							( ( subjectCertInfoPtr->subjectName != NULL ) ? \
663 									  PRE_CHECK_DN_PARTIAL : 0 ),
664 									  PRE_FLAG_NONE );
665 		if( cryptStatusError( status ) )
666 			return( status );
667 		}
668 
669 	/* Determine how big the encoded certificate request will be */
670 	payloadLength = subjectCertInfoPtr->publicKeyInfoSize;
671 	if( subjectCertInfoPtr->subjectName != NULL )
672 		{
673 		status = subjectDNsize = sizeofDN( subjectCertInfoPtr->subjectName );
674 		if( cryptStatusError( status ) )
675 			return( status );
676 		subjectCertInfoPtr->subjectDNsize = subjectDNsize;
677 		payloadLength += sizeofObject( subjectDNsize );
678 		}
679 	if( subjectCertInfoPtr->startTime > MIN_TIME_VALUE )
680 		timeSize = sizeofObject( sizeofGeneralizedTime() );
681 	if( subjectCertInfoPtr->endTime > MIN_TIME_VALUE )
682 		timeSize += sizeofObject( sizeofGeneralizedTime() );
683 	if( timeSize > 0 )
684 		payloadLength += sizeofObject( timeSize );
685 	extensionSize = sizeofAttributes( subjectCertInfoPtr->attributes,
686 									  CRYPT_CERTTYPE_REQUEST_CERT );
687 	if( cryptStatusError( extensionSize ) )
688 		return( extensionSize );
689 	if( extensionSize > 0 )
690 		payloadLength += sizeofObject( extensionSize );
691 
692 	/* Write the header, request ID, inner header, DN, and public key */
693 	writeSequence( stream, sizeofShortInteger( 0 ) + \
694 				   sizeofObject( payloadLength ) );
695 	writeShortInteger( stream, 0, DEFAULT_TAG );
696 	writeSequence( stream, payloadLength );
697 	if( timeSize > 0 )
698 		{
699 		writeConstructed( stream, timeSize, CTAG_CF_VALIDITY );
700 		if( subjectCertInfoPtr->startTime > MIN_TIME_VALUE )
701 			{
702 			writeConstructed( stream, sizeofGeneralizedTime(), 0 );
703 			writeGeneralizedTime( stream, subjectCertInfoPtr->startTime,
704 								  DEFAULT_TAG );
705 			}
706 		if( subjectCertInfoPtr->endTime > MIN_TIME_VALUE )
707 			{
708 			writeConstructed( stream, sizeofGeneralizedTime(), 1 );
709 			writeGeneralizedTime( stream, subjectCertInfoPtr->endTime,
710 								  DEFAULT_TAG );
711 			}
712 		}
713 	if( subjectDNsize > 0 )
714 		{
715 		writeConstructed( stream, subjectCertInfoPtr->subjectDNsize,
716 						  CTAG_CF_SUBJECT );
717 		status = writeDN( stream, subjectCertInfoPtr->subjectName,
718 						  DEFAULT_TAG );
719 		if( cryptStatusError( status ) )
720 			return( status );
721 		}
722 	sputc( stream, MAKE_CTAG( CTAG_CF_PUBLICKEY ) );
723 		   	/* Convert the SPKI SEQUENCE tag to the CRMF alternative */
724 	swrite( stream, ( BYTE * ) subjectCertInfoPtr->publicKeyInfo + 1,
725 			subjectCertInfoPtr->publicKeyInfoSize - 1 );
726 	if( cryptStatusError( status ) || extensionSize <= 0 )
727 		return( status );
728 
729 	/* Write the attributes */
730 	writeConstructed( stream, extensionSize, CTAG_CF_EXTENSIONS );
731 	return( writeAttributes( stream, subjectCertInfoPtr->attributes,
732 							 CRYPT_CERTTYPE_REQUEST_CERT, extensionSize ) );
733 	}
734 
735 /* Write CRMF revocation request information:
736 
737 	RevDetails ::= SEQUENCE {
738 		certTemplate			SEQUENCE {
739 			serialNumber  [ 1 ]	INTEGER,
740 			issuer		  [ 3 ]	EXPLICIT Name,
741 			},
742 		crlEntryDetails			SET OF Attribute
743 		} */
744 
745 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
writeRevRequestInfo(INOUT STREAM * stream,INOUT CERT_INFO * subjectCertInfoPtr,STDC_UNUSED const CERT_INFO * issuerCertInfoPtr,STDC_UNUSED const CRYPT_CONTEXT iIssuerCryptContext)746 static int writeRevRequestInfo( INOUT STREAM *stream,
747 								INOUT CERT_INFO *subjectCertInfoPtr,
748 								STDC_UNUSED const CERT_INFO *issuerCertInfoPtr,
749 								STDC_UNUSED const CRYPT_CONTEXT iIssuerCryptContext )
750 	{
751 	int payloadLength, extensionSize, status;
752 
753 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
754 	assert( isWritePtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
755 
756 	REQUIRES( issuerCertInfoPtr == NULL );
757 	REQUIRES( iIssuerCryptContext == CRYPT_UNUSED );
758 
759 	/* Make sure that everything is in order */
760 	if( sIsNullStream( stream ) )
761 		{
762 		status = preCheckCertificate( subjectCertInfoPtr, NULL,
763 									  PRE_CHECK_ISSUERDN | PRE_CHECK_SERIALNO,
764 									  PRE_FLAG_NONE );
765 		if( cryptStatusError( status ) )
766 			return( status );
767 		}
768 
769 	/* Determine how big the encoded certificate request will be */
770 	extensionSize = sizeofAttributes( subjectCertInfoPtr->attributes,
771 									  CRYPT_CERTTYPE_REQUEST_REVOCATION );
772 	if( cryptStatusError( extensionSize ) )
773 		return( extensionSize );
774 	payloadLength = sizeofInteger( subjectCertInfoPtr->cCertCert->serialNumber,
775 								   subjectCertInfoPtr->cCertCert->serialNumberLength ) + \
776 					sizeofObject( subjectCertInfoPtr->issuerDNsize );
777 	if( extensionSize > 0 )
778 		payloadLength += sizeofObject( extensionSize );
779 
780 	/* Write the header, inner header, serial number and issuer DN */
781 	writeSequence( stream, sizeofObject( payloadLength ) );
782 	writeSequence( stream, payloadLength );
783 	writeInteger( stream, subjectCertInfoPtr->cCertCert->serialNumber,
784 				  subjectCertInfoPtr->cCertCert->serialNumberLength,
785 				  CTAG_CF_SERIALNUMBER );
786 	writeConstructed( stream, subjectCertInfoPtr->issuerDNsize,
787 					  CTAG_CF_ISSUER );
788 	status = swrite( stream, subjectCertInfoPtr->issuerDNptr,
789 					 subjectCertInfoPtr->issuerDNsize );
790 	if( cryptStatusError( status ) || extensionSize <= 0 )
791 		return( status );
792 
793 	/* Write the attributes */
794 	writeConstructed( stream, extensionSize, CTAG_CF_EXTENSIONS );
795 	return( writeAttributes( stream, subjectCertInfoPtr->attributes,
796 							 CRYPT_CERTTYPE_REQUEST_REVOCATION, extensionSize ) );
797 	}
798 #endif /* USE_CERTREQ */
799 
800 /****************************************************************************
801 *																			*
802 *						Write Validity-checking Objects						*
803 *																			*
804 ****************************************************************************/
805 
806 #ifdef USE_CERTVAL
807 
808 /* Write an RTCS request:
809 
810 	RTCSRequests ::= SEQUENCE {
811 		SEQUENCE OF SEQUENCE {
812 			certHash	OCTET STRING SIZE(20)
813 			},
814 		attributes		Attributes OPTIONAL
815 		} */
816 
817 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
writeRtcsRequestInfo(INOUT STREAM * stream,INOUT CERT_INFO * subjectCertInfoPtr,STDC_UNUSED const CERT_INFO * issuerCertInfoPtr,STDC_UNUSED const CRYPT_CONTEXT iIssuerCryptContext)818 static int writeRtcsRequestInfo( INOUT STREAM *stream,
819 								 INOUT CERT_INFO *subjectCertInfoPtr,
820 								 STDC_UNUSED const CERT_INFO *issuerCertInfoPtr,
821 								 STDC_UNUSED \
822 									const CRYPT_CONTEXT iIssuerCryptContext )
823 	{
824 	CERT_VAL_INFO *certValInfo = subjectCertInfoPtr->cCertVal;
825 	VALIDITY_INFO *validityInfo;
826 	int length, extensionSize, requestInfoLength = 0;
827 	int iterationCount, status;
828 
829 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
830 	assert( isWritePtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
831 
832 	REQUIRES( issuerCertInfoPtr == NULL );
833 	REQUIRES( iIssuerCryptContext == CRYPT_UNUSED );
834 
835 	/* Perform any necessary pre-encoding steps */
836 	if( sIsNullStream( stream ) )
837 		{
838 		/* Generate a fresh nonce for the request */
839 		status = setNonce( &subjectCertInfoPtr->attributes,
840 						   CRYPT_CERTINFO_CMS_NONCE );
841 		if( cryptStatusError( status ) )
842 			return( status );
843 
844 		/* Perform the pre-encoding checks */
845 		status = preCheckCertificate( subjectCertInfoPtr, NULL,
846 									  PRE_CHECK_VALENTRIES, PRE_FLAG_NONE );
847 		if( cryptStatusError( status ) )
848 			return( status );
849 		}
850 
851 	/* Determine how big the encoded RTCS request will be */
852 	for( validityInfo = certValInfo->validityInfo, iterationCount = 0;
853 		 validityInfo != NULL && \
854 			iterationCount < FAILSAFE_ITERATIONS_LARGE;
855 		 validityInfo = validityInfo->next, iterationCount++ )
856 		{
857 		const int requestEntrySize = sizeofRtcsRequestEntry( validityInfo );
858 
859 		if( cryptStatusError( requestEntrySize ) )
860 			return( requestEntrySize );
861 		requestInfoLength += requestEntrySize;
862 		}
863 	ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
864 	extensionSize = sizeofAttributes( subjectCertInfoPtr->attributes,
865 									  CRYPT_CERTTYPE_RTCS_REQUEST );
866 	if( cryptStatusError( extensionSize ) )
867 		return( extensionSize );
868 	length = sizeofObject( requestInfoLength ) + \
869 			 ( ( extensionSize > 0 ) ? sizeofObject( extensionSize ) : 0 );
870 
871 	/* Write the outer SEQUENCE wrapper */
872 	writeSequence( stream, length );
873 
874 	/* Write the SEQUENCE OF request wrapper and the request information */
875 	status = writeSequence( stream, requestInfoLength );
876 	for( validityInfo = certValInfo->validityInfo, iterationCount = 0;
877 		 cryptStatusOK( status ) && validityInfo != NULL && \
878 			iterationCount < FAILSAFE_ITERATIONS_LARGE;
879 		 validityInfo = validityInfo->next, iterationCount++ )
880 		{
881 		status = writeRtcsRequestEntry( stream, validityInfo );
882 		}
883 	ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
884 	if( cryptStatusError( status ) || extensionSize <= 0 )
885 		return( status );
886 
887 	/* Write the attributes */
888 	return( writeAttributes( stream, subjectCertInfoPtr->attributes,
889 							 CRYPT_CERTTYPE_RTCS_REQUEST, extensionSize ) );
890 	}
891 
892 /* Write an RTCS response:
893 
894 	RTCSResponse ::= SEQUENCE OF SEQUENCE {
895 		certHash	OCTET STRING SIZE(20),
896 		RESPONSEINFO
897 		} */
898 
899 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
writeRtcsResponseInfo(INOUT STREAM * stream,INOUT CERT_INFO * subjectCertInfoPtr,STDC_UNUSED const CERT_INFO * issuerCertInfoPtr,STDC_UNUSED const CRYPT_CONTEXT iIssuerCryptContext)900 static int writeRtcsResponseInfo( INOUT STREAM *stream,
901 								  INOUT CERT_INFO *subjectCertInfoPtr,
902 								  STDC_UNUSED const CERT_INFO *issuerCertInfoPtr,
903 								  STDC_UNUSED \
904 									const CRYPT_CONTEXT iIssuerCryptContext )
905 	{
906 	CERT_VAL_INFO *certValInfo = subjectCertInfoPtr->cCertVal;
907 	VALIDITY_INFO *validityInfo;
908 	int extensionSize, validityInfoLength = 0, iterationCount, status;
909 
910 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
911 	assert( isWritePtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
912 
913 	REQUIRES( issuerCertInfoPtr == NULL );
914 	REQUIRES( iIssuerCryptContext == CRYPT_UNUSED );
915 
916 	/* RTCS can legitimately return an empty response if there's a problem
917 	   with the responder so we don't require that any responses be present
918 	   as for CRLs/OCSP */
919 
920 	/* Perform any necessary pre-encoding steps */
921 	if( sIsNullStream( stream ) )
922 		{
923 		status = preEncodeCertificate( subjectCertInfoPtr, NULL,
924 									   PRE_SET_VALINFO );
925 		if( cryptStatusError( status ) )
926 			return( status );
927 		}
928 
929 	/* Determine how big the encoded RTCS response will be */
930 	for( validityInfo = certValInfo->validityInfo, iterationCount = 0;
931 		 validityInfo != NULL && iterationCount < FAILSAFE_ITERATIONS_LARGE;
932 		 validityInfo = validityInfo->next, iterationCount++ )
933 		{
934 		const int responseEntrySize = \
935 			sizeofRtcsResponseEntry( validityInfo,
936 				( certValInfo->responseType == RTCSRESPONSE_TYPE_EXTENDED ) ? \
937 				TRUE : FALSE );
938 
939 		if( cryptStatusError( responseEntrySize ) )
940 			return( responseEntrySize );
941 		validityInfoLength += responseEntrySize;
942 		}
943 	ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
944 	extensionSize = sizeofAttributes( subjectCertInfoPtr->attributes,
945 									  CRYPT_CERTTYPE_RTCS_RESPONSE );
946 	if( cryptStatusError( extensionSize ) )
947 		return( extensionSize );
948 
949 	/* Write the SEQUENCE OF status information wrapper and the certificate
950 	   status information */
951 	status = writeSequence( stream, validityInfoLength );
952 	for( validityInfo = certValInfo->validityInfo, iterationCount = 0;
953 		 cryptStatusOK( status ) && validityInfo != NULL && \
954 			iterationCount < FAILSAFE_ITERATIONS_LARGE;
955 		 validityInfo = validityInfo->next, iterationCount++ )
956 		{
957 		status = writeRtcsResponseEntry( stream, validityInfo,
958 					( certValInfo->responseType == RTCSRESPONSE_TYPE_EXTENDED ) ? \
959 					TRUE : FALSE );
960 		}
961 	ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
962 	if( cryptStatusError( status ) || extensionSize <= 0 )
963 		return( status );
964 
965 	/* Write the attributes */
966 	return( writeAttributes( stream, subjectCertInfoPtr->attributes,
967 							 CRYPT_CERTTYPE_RTCS_RESPONSE, extensionSize ) );
968 	}
969 #endif /* USE_CERTVAL */
970 
971 /****************************************************************************
972 *																			*
973 *						Write Revocation-checking Objects					*
974 *																			*
975 ****************************************************************************/
976 
977 #ifdef USE_CERTREV
978 
979 /* Write an OCSP request:
980 
981 	OCSPRequest ::= SEQUENCE {				-- Write, v1
982 		reqName		[1]	EXPLICIT [4] EXPLICIT DirectoryName OPTIONAL,
983 		reqList			SEQUENCE OF SEQUENCE {
984 						SEQUENCE {			-- certID
985 			hashAlgo	AlgorithmIdentifier,
986 			iNameHash	OCTET STRING,
987 			iKeyHash	OCTET STRING,
988 			serialNo	INTEGER
989 			} }
990 		}
991 
992 	OCSPRequest ::= SEQUENCE {				-- Write, v2 (not used)
993 		version		[0]	EXPLICIT INTEGER (1),
994 		reqName		[1]	EXPLICIT [4] EXPLICIT DirectoryName OPTIONAL,
995 		reqList			SEQUENCE OF SEQUENCE {
996 			certID	[2]	EXPLICIT OCTET STRING	-- Certificate hash
997 			}
998 		} */
999 
1000 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
writeOcspRequestInfo(INOUT STREAM * stream,INOUT CERT_INFO * subjectCertInfoPtr,IN_OPT const CERT_INFO * issuerCertInfoPtr,IN_HANDLE_OPT const CRYPT_CONTEXT iIssuerCryptContext)1001 static int writeOcspRequestInfo( INOUT STREAM *stream,
1002 								 INOUT CERT_INFO *subjectCertInfoPtr,
1003 								 IN_OPT const CERT_INFO *issuerCertInfoPtr,
1004 								 IN_HANDLE_OPT \
1005 									const CRYPT_CONTEXT iIssuerCryptContext )
1006 	{
1007 	CERT_REV_INFO *certRevInfo = subjectCertInfoPtr->cCertRev;
1008 	REVOCATION_INFO *revocationInfo;
1009 	int length, extensionSize, revocationInfoLength = 0;
1010 	int iterationCount, status;
1011 
1012 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
1013 	assert( isWritePtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
1014 	assert( issuerCertInfoPtr == NULL || \
1015 			isReadPtr( issuerCertInfoPtr, sizeof( CERT_INFO ) ) );
1016 
1017 	REQUIRES( iIssuerCryptContext == CRYPT_UNUSED || \
1018 			  isHandleRangeValid( iIssuerCryptContext ) );/* Not used here */
1019 
1020 	/* Perform any necessary pre-encoding steps */
1021 	if( sIsNullStream( stream ) )
1022 		{
1023 		/* Generate a fresh nonce for the request */
1024 		status = setNonce( &subjectCertInfoPtr->attributes,
1025 						   CRYPT_CERTINFO_OCSP_NONCE );
1026 		if( cryptStatusError( status ) )
1027 			return( status );
1028 
1029 		/* Perform the pre-encoding checks */
1030 		status = preEncodeCertificate( subjectCertInfoPtr, issuerCertInfoPtr,
1031 									   PRE_SET_REVINFO );
1032 		if( cryptStatusError( status ) )
1033 			return( status );
1034 		if( issuerCertInfoPtr != NULL )
1035 			{
1036 			/* It's a signed request, there has to be an issuer DN present */
1037 			status = preCheckCertificate( subjectCertInfoPtr,
1038 										  issuerCertInfoPtr,
1039 										  PRE_CHECK_ISSUERDN | \
1040 										  PRE_CHECK_REVENTRIES,
1041 										  PRE_FLAG_DN_IN_ISSUERCERT );
1042 			}
1043 		else
1044 			{
1045 			status = preCheckCertificate( subjectCertInfoPtr, NULL,
1046 										  PRE_CHECK_REVENTRIES,
1047 										  PRE_FLAG_NONE );
1048 			}
1049 		if( cryptStatusError( status ) )
1050 			return( status );
1051 		}
1052 
1053 	/* Determine how big the encoded OCSP request will be */
1054 	for( revocationInfo = certRevInfo->revocations, iterationCount = 0;
1055 		 revocationInfo != NULL && \
1056 			iterationCount < FAILSAFE_ITERATIONS_LARGE;
1057 		 revocationInfo = revocationInfo->next, iterationCount++ )
1058 		{
1059 		int requestEntrySize;
1060 
1061 		status = requestEntrySize = sizeofOcspRequestEntry( revocationInfo );
1062 		if( cryptStatusError( status ) )
1063 			return( status );
1064 		revocationInfoLength += requestEntrySize;
1065 		}
1066 	ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
1067 	status = extensionSize = \
1068 					sizeofAttributes( subjectCertInfoPtr->attributes,
1069 									  CRYPT_CERTTYPE_OCSP_REQUEST );
1070 	if( cryptStatusError( status ) )
1071 		return( status );
1072 	length = ( ( subjectCertInfoPtr->version == 2 ) ? \
1073 				 sizeofObject( sizeofShortInteger( CTAG_OR_VERSION ) ) : 0 ) + \
1074 			 ( ( issuerCertInfoPtr != NULL ) ? \
1075 				 sizeofObject( sizeofObject( issuerCertInfoPtr->subjectDNsize ) ) : 0 ) + \
1076 			 sizeofObject( revocationInfoLength );
1077 	if( extensionSize > 0 )
1078 		length += sizeofObject( sizeofObject( extensionSize ) );
1079 
1080 	/* Write the outer SEQUENCE wrapper */
1081 	writeSequence( stream, length );
1082 
1083 	/* If we're using v2 identifiers, mark this as a v2 request */
1084 	if( subjectCertInfoPtr->version == 2 )
1085 		{
1086 		writeConstructed( stream, sizeofShortInteger( 1 ), CTAG_OR_VERSION );
1087 		writeShortInteger( stream, 1, DEFAULT_TAG );
1088 		}
1089 
1090 	/* If we're signing the request, write the issuer DN as a GeneralName */
1091 	if( issuerCertInfoPtr != NULL )
1092 		{
1093 		writeConstructed( stream,
1094 						  sizeofObject( issuerCertInfoPtr->subjectDNsize ), 1 );
1095 		writeConstructed( stream, issuerCertInfoPtr->subjectDNsize, 4 );
1096 		status = swrite( stream, issuerCertInfoPtr->subjectDNptr,
1097 						 issuerCertInfoPtr->subjectDNsize );
1098 		if( cryptStatusError( status ) )
1099 			return( status );
1100 		}
1101 
1102 	/* Write the SEQUENCE OF revocation information wrapper and the
1103 	   revocation information */
1104 	status = writeSequence( stream, revocationInfoLength );
1105 	for( revocationInfo = certRevInfo->revocations, iterationCount = 0;
1106 		 cryptStatusOK( status ) && revocationInfo != NULL && \
1107 			iterationCount < FAILSAFE_ITERATIONS_LARGE;
1108 		 revocationInfo = revocationInfo->next, iterationCount++ )
1109 		{
1110 		status = writeOcspRequestEntry( stream, revocationInfo );
1111 		}
1112 	ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
1113 	if( cryptStatusError( status ) || extensionSize <= 0 )
1114 		return( status );
1115 
1116 	/* Write the attributes */
1117 	return( writeAttributes( stream, subjectCertInfoPtr->attributes,
1118 							 CRYPT_CERTTYPE_OCSP_REQUEST, extensionSize ) );
1119 	}
1120 
1121 /* Write an OCSP response:
1122 
1123 	OCSPResponse ::= SEQUENCE {
1124 		version		[0]	EXPLICIT INTEGER (1),
1125 		respID		[1]	EXPLICIT Name,
1126 		producedAt		GeneralizedTime,
1127 		responses		SEQUENCE OF Response
1128 		exts		[1]	EXPLICIT Extensions OPTIONAL,
1129 		} */
1130 
1131 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
writeOcspResponseInfo(INOUT STREAM * stream,INOUT CERT_INFO * subjectCertInfoPtr,const CERT_INFO * issuerCertInfoPtr,IN_HANDLE const CRYPT_CONTEXT iIssuerCryptContext)1132 static int writeOcspResponseInfo( INOUT STREAM *stream,
1133 								  INOUT CERT_INFO *subjectCertInfoPtr,
1134 								  const CERT_INFO *issuerCertInfoPtr,
1135 								  IN_HANDLE \
1136 									const CRYPT_CONTEXT iIssuerCryptContext )
1137 	{
1138 	CERT_REV_INFO *certRevInfo = subjectCertInfoPtr->cCertRev;
1139 	REVOCATION_INFO *revocationInfo;
1140 	int length, extensionSize, revocationInfoLength = 0;
1141 	int iterationCount, status;
1142 
1143 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
1144 	assert( isWritePtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
1145 	assert( isReadPtr( issuerCertInfoPtr, sizeof( CERT_INFO ) ) );
1146 
1147 	REQUIRES( isHandleRangeValid( iIssuerCryptContext ) );/* Not used here */
1148 
1149 	/* Perform any necessary pre-encoding steps */
1150 	if( sIsNullStream( stream ) )
1151 		{
1152 		status = preCheckCertificate( subjectCertInfoPtr, issuerCertInfoPtr,
1153 									  PRE_CHECK_ISSUERDN | \
1154 									  PRE_CHECK_REVENTRIES,
1155 									  PRE_FLAG_DN_IN_ISSUERCERT );
1156 		if( cryptStatusError( status ) )
1157 			return( status );
1158 		}
1159 
1160 	/* Determine how big the encoded OCSP response will be */
1161 	for( revocationInfo = certRevInfo->revocations, iterationCount = 0;
1162 		 revocationInfo != NULL && \
1163 			iterationCount < FAILSAFE_ITERATIONS_LARGE;
1164 		 revocationInfo = revocationInfo->next, iterationCount++ )
1165 		{
1166 		int responseEntrySize;
1167 
1168 		status = responseEntrySize = sizeofOcspResponseEntry( revocationInfo );
1169 		if( cryptStatusError( status ) )
1170 			return( status );
1171 		revocationInfoLength += responseEntrySize;
1172 		}
1173 	ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
1174 	status = extensionSize = \
1175 					sizeofAttributes( subjectCertInfoPtr->attributes,
1176 									  CRYPT_CERTTYPE_OCSP_RESPONSE );
1177 	if( cryptStatusError( status ) )
1178 		return( status );
1179 	length = sizeofObject( sizeofShortInteger( CTAG_OP_VERSION ) ) + \
1180 			 sizeofObject( issuerCertInfoPtr->subjectDNsize ) + \
1181 			 sizeofGeneralizedTime() + \
1182 			 sizeofObject( revocationInfoLength );
1183 	if( extensionSize > 0 )
1184 		length += sizeofObject( sizeofObject( extensionSize ) );
1185 
1186 	/* Write the outer SEQUENCE wrapper, version, and issuer DN and
1187 	   producedAt time */
1188 	writeSequence( stream, length );
1189 	writeConstructed( stream, sizeofShortInteger( 1 ), CTAG_OP_VERSION );
1190 	writeShortInteger( stream, 1, DEFAULT_TAG );
1191 	writeConstructed( stream, issuerCertInfoPtr->subjectDNsize, 1 );
1192 	swrite( stream, issuerCertInfoPtr->subjectDNptr,
1193 			issuerCertInfoPtr->subjectDNsize );
1194 	status = writeGeneralizedTime( stream, subjectCertInfoPtr->startTime,
1195 								   DEFAULT_TAG );
1196 	if( cryptStatusError( status ) )
1197 		return( status );
1198 
1199 	/* Write the SEQUENCE OF revocation information wrapper and the
1200 	   revocation information */
1201 	status = writeSequence( stream, revocationInfoLength );
1202 	for( revocationInfo = certRevInfo->revocations, iterationCount = 0;
1203 		 cryptStatusOK( status ) && revocationInfo != NULL && \
1204 			iterationCount < FAILSAFE_ITERATIONS_LARGE;
1205 		 revocationInfo = revocationInfo->next, iterationCount++ )
1206 		{
1207 		status = writeOcspResponseEntry( stream, revocationInfo,
1208 										 subjectCertInfoPtr->startTime );
1209 		}
1210 	ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
1211 	if( cryptStatusError( status ) || extensionSize <= 0 )
1212 		return( status );
1213 
1214 	/* Write the attributes */
1215 	return( writeAttributes( stream, subjectCertInfoPtr->attributes,
1216 							 CRYPT_CERTTYPE_OCSP_RESPONSE, extensionSize ) );
1217 	}
1218 #endif /* USE_CERTREV */
1219 
1220 /****************************************************************************
1221 *																			*
1222 *						Write CMS Attribute Objects							*
1223 *																			*
1224 ****************************************************************************/
1225 
1226 #ifdef USE_CMSATTR
1227 
1228 /* Write CMS attributes */
1229 
1230 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
writeCmsAttributes(INOUT STREAM * stream,INOUT CERT_INFO * attributeInfoPtr,STDC_UNUSED const CERT_INFO * issuerCertInfoPtr,STDC_UNUSED const CRYPT_CONTEXT iIssuerCryptContext)1231 static int writeCmsAttributes( INOUT STREAM *stream,
1232 							   INOUT CERT_INFO *attributeInfoPtr,
1233 							   STDC_UNUSED const CERT_INFO *issuerCertInfoPtr,
1234 							   STDC_UNUSED const CRYPT_CONTEXT iIssuerCryptContext )
1235 	{
1236 	int addDefaultAttributes, attributeSize, status;
1237 
1238 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
1239 	assert( isWritePtr( attributeInfoPtr, sizeof( CERT_INFO ) ) );
1240 
1241 	REQUIRES( issuerCertInfoPtr == NULL );
1242 	REQUIRES( iIssuerCryptContext == CRYPT_UNUSED );
1243 	REQUIRES( attributeInfoPtr->attributes != NULL );
1244 
1245 	status = krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE,
1246 							  IMESSAGE_GETATTRIBUTE, &addDefaultAttributes,
1247 							  CRYPT_OPTION_CMS_DEFAULTATTRIBUTES );
1248 	if( cryptStatusError( status ) )
1249 		return( status );
1250 
1251 	/* Make sure that there's a hash and content type present */
1252 	if( findAttributeField( attributeInfoPtr->attributes,
1253 							CRYPT_CERTINFO_CMS_MESSAGEDIGEST,
1254 							CRYPT_ATTRIBUTE_NONE ) == NULL )
1255 		{
1256 		setErrorInfo( attributeInfoPtr, CRYPT_CERTINFO_CMS_MESSAGEDIGEST,
1257 					  CRYPT_ERRTYPE_ATTR_ABSENT );
1258 		return( CRYPT_ERROR_INVALID );
1259 		}
1260 	if( !checkAttributePresent( attributeInfoPtr->attributes,
1261 								CRYPT_CERTINFO_CMS_CONTENTTYPE ) )
1262 		{
1263 		const int value = CRYPT_CONTENT_DATA;
1264 
1265 		/* If there's no content type and we're not adding it automatically,
1266 		   complain */
1267 		if( !addDefaultAttributes )
1268 			{
1269 			setErrorInfo( attributeInfoPtr, CRYPT_CERTINFO_CMS_CONTENTTYPE,
1270 						  CRYPT_ERRTYPE_ATTR_ABSENT );
1271 			return( CRYPT_ERROR_INVALID );
1272 			}
1273 
1274 		/* There's no content type present, treat it as straight data (which
1275 		   means that this is signedData) */
1276 		status = addCertComponent( attributeInfoPtr,
1277 								   CRYPT_CERTINFO_CMS_CONTENTTYPE, value );
1278 		if( cryptStatusError( status ) )
1279 			return( status );
1280 		}
1281 
1282 	/* If there's no signing time attribute present and we're adding the
1283 	   default attributes, add it now.  This will usually already have been
1284 	   added by the caller via getReliableTime(), if it hasn't then we
1285 	   default to using the system time source because the signing object
1286 	   isn't available at this point to provide a time source */
1287 	if( addDefaultAttributes && \
1288 		!checkAttributePresent( attributeInfoPtr->attributes,
1289 								CRYPT_CERTINFO_CMS_SIGNINGTIME ) )
1290 		{
1291 		const time_t currentTime = getTime();
1292 
1293 		/* If the time is screwed up then we can't provide a signed
1294 		   indication of the time */
1295 		if( currentTime <= MIN_TIME_VALUE )
1296 			{
1297 			setErrorInfo( attributeInfoPtr, CRYPT_CERTINFO_VALIDFROM,
1298 						  CRYPT_ERRTYPE_ATTR_VALUE );
1299 			return( CRYPT_ERROR_NOTINITED );
1300 			}
1301 
1302 		status = addCertComponentString( attributeInfoPtr,
1303 										 CRYPT_CERTINFO_CMS_SIGNINGTIME,
1304 										 &currentTime, sizeof( time_t ) );
1305 		if( cryptStatusError( status ) )
1306 			return( status );
1307 		}
1308 
1309 	/* Check that the attributes are in order and determine how big the whole
1310 	   mess will be */
1311 	status = checkAttributes( ATTRIBUTE_CMS, attributeInfoPtr->attributes,
1312 							  &attributeInfoPtr->errorLocus,
1313 							  &attributeInfoPtr->errorType );
1314 	if( cryptStatusError( status ) )
1315 		return( status );
1316 	attributeSize = sizeofAttributes( attributeInfoPtr->attributes,
1317 									  CRYPT_CERTTYPE_CMS_ATTRIBUTES );
1318 	if( cryptStatusError( attributeSize ) || attributeSize <= 0 )
1319 		return( attributeSize );
1320 
1321 	/* Write the attributes */
1322 	return( writeAttributes( stream, attributeInfoPtr->attributes,
1323 							 CRYPT_CERTTYPE_CMS_ATTRIBUTES, attributeSize ) );
1324 	}
1325 #endif /* USE_CMSATTR */
1326 
1327 /****************************************************************************
1328 *																			*
1329 *							Write PKI User Objects							*
1330 *																			*
1331 ****************************************************************************/
1332 
1333 #ifdef USE_PKIUSER
1334 
1335 /* Write PKI user information:
1336 
1337 	userData ::= SEQUENCE {
1338 		name				Name,			-- Name for CMP
1339 		encAlgo				AlgorithmIdentifier,-- Algo to encrypt passwords
1340 		encPW				OCTET STRING,	-- Encrypted passwords
1341 		certAttributes		Attributes		-- Certificate attributes
1342 		userAttributes		SEQUENCE {		-- PKI user attributes
1343 			isRA			BOOLEAN OPTIONAL -- Whether user is an RA
1344 			} OPTIONAL
1345 		} */
1346 
1347 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4, 5, 7 ) ) \
1348 static int createPkiUserInfo( INOUT CERT_PKIUSER_INFO *certUserInfo,
1349 							  OUT_BUFFER( maxUserInfoSize, *userInfoSize ) \
1350 									BYTE *userInfo,
1351 							  IN_LENGTH_SHORT_MIN( 64 ) \
1352 									const int maxUserInfoSize,
1353 							  OUT_LENGTH_BOUNDED_Z( maxUserInfoSize ) \
1354 									int *userInfoSize,
1355 							  OUT_BUFFER( maxAlgoIdSize, *algoIdSize ) \
1356 									BYTE *algoID,
1357 							  IN_LENGTH_SHORT_MIN( 16 ) \
1358 									const int maxAlgoIdSize,
1359 							  OUT_LENGTH_BOUNDED_Z( maxAlgoIdSize ) \
1360 									int *algoIdSize )
1361 	{
1362 	CRYPT_CONTEXT iCryptContext;
1363 	MESSAGE_CREATEOBJECT_INFO createInfo;
1364 	MESSAGE_DATA msgData;
1365 	STREAM stream;
1366 	static const int mode = CRYPT_MODE_CFB;	/* enum vs.int */
1367 	int userInfoBufPos DUMMY_INIT, i, status;
1368 
1369 	assert( isWritePtr( certUserInfo, sizeof( CERT_PKIUSER_INFO ) ) );
1370 	assert( isWritePtr( userInfo, maxUserInfoSize ) );
1371 	assert( isWritePtr( userInfoSize, sizeof( int ) ) );
1372 	assert( isWritePtr( algoID, maxAlgoIdSize ) );
1373 	assert( isWritePtr( algoIdSize, sizeof( int ) ) );
1374 
1375 	REQUIRES( maxUserInfoSize >= 64 && \
1376 			  maxUserInfoSize < MAX_INTLENGTH_SHORT );
1377 	REQUIRES( maxAlgoIdSize >= 16 && maxAlgoIdSize < MAX_INTLENGTH_SHORT );
1378 
1379 	/* Clear return values */
1380 	memset( userInfo, 0, maxUserInfoSize );
1381 	memset( algoID, 0, maxAlgoIdSize );
1382 	*userInfoSize = *algoIdSize = 0;
1383 
1384 	/* Create a stream-cipher encryption context and use it to generate the
1385 	   user passwords.  These aren't encryption keys but just authenticators
1386 	   used for MACing so we don't go to the usual extremes to protect them.
1387 	   In addition we can't use the most obvious option for the stream
1388 	   cipher, RC4, because it may be disabled in some builds.  Instead we
1389 	   rely on 3DES, which is always available */
1390 	setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_3DES );
1391 	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
1392 							  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
1393 							  OBJECT_TYPE_CONTEXT );
1394 	if( cryptStatusError( status ) )
1395 		return( status );
1396 	iCryptContext = createInfo.cryptHandle;
1397 	status = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE,
1398 							  ( MESSAGE_CAST ) &mode, CRYPT_CTXINFO_MODE );
1399 	if( cryptStatusOK( status ) )
1400 		status = krnlSendNotifier( iCryptContext, IMESSAGE_CTX_GENKEY );
1401 	if( cryptStatusOK( status ) )
1402 		status = krnlSendNotifier( iCryptContext, IMESSAGE_CTX_GENIV );
1403 	if( cryptStatusError( status ) )
1404 		{
1405 		krnlSendNotifier( iCryptContext, IMESSAGE_DECREFCOUNT );
1406 		return( status );
1407 		}
1408 
1409 	/* Create the PKI user authenticators */
1410 	memset( certUserInfo->pkiIssuePW, 0, PKIUSER_AUTHENTICATOR_SIZE );
1411 	status = krnlSendMessage( iCryptContext, IMESSAGE_CTX_ENCRYPT,
1412 							  certUserInfo->pkiIssuePW,
1413 							  PKIUSER_AUTHENTICATOR_SIZE );
1414 	if( cryptStatusOK( status ) )
1415 		{
1416 		memset( certUserInfo->pkiRevPW, 0, PKIUSER_AUTHENTICATOR_SIZE );
1417 		status = krnlSendMessage( iCryptContext, IMESSAGE_CTX_ENCRYPT,
1418 								  certUserInfo->pkiRevPW,
1419 								  PKIUSER_AUTHENTICATOR_SIZE );
1420 		}
1421 	krnlSendNotifier( iCryptContext, IMESSAGE_DECREFCOUNT );
1422 	if( cryptStatusError( status ) )
1423 		return( status );
1424 
1425 	/* Encode the user information so that it can be encrypted */
1426 	sMemOpen( &stream, userInfo, maxUserInfoSize );
1427 	writeSequence( &stream, 2 * sizeofObject( PKIUSER_AUTHENTICATOR_SIZE ) );
1428 	writeOctetString( &stream, certUserInfo->pkiIssuePW,
1429 					  PKIUSER_AUTHENTICATOR_SIZE, DEFAULT_TAG );
1430 	status = writeOctetString( &stream, certUserInfo->pkiRevPW,
1431 							   PKIUSER_AUTHENTICATOR_SIZE, DEFAULT_TAG );
1432 	if( cryptStatusOK( status ) )
1433 		userInfoBufPos = stell( &stream );
1434 	sMemDisconnect( &stream );
1435 	if( cryptStatusError( status ) )
1436 		return( status );
1437 
1438 	/* Encrypt (or at least mask) the user information.  For forwards
1439 	   compatibility (and because the format requires the use of some form
1440 	   of encryption when encoding the data) we encrypt the user data, once
1441 	   user roles are fully implemented this can use the data storage key
1442 	   associated with the CA user to perform the encryption instead of a
1443 	   fixed interop key.  This isn't a security issue because the CA
1444 	   database is assumed to be secure (or at least the CA is in serious
1445 	   trouble if its database isn't secured), we encrypt because it's
1446 	   pretty much free and because it doesn't hurt either way.  Most CA
1447 	   guidelines merely require that the CA protect its user database via
1448 	   standard (physical/ACL) security measures so this is no less secure
1449 	   than what's required by various CA guidelines.
1450 
1451 	   When we do this for real we probably need an extra level of
1452 	   indirection to go from the CA secret to the database decryption key
1453 	   so that we can change the encryption algorithm and so that we don't
1454 	   have to directly apply the CA's data storage key to the user
1455 	   database */
1456 	setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_3DES );
1457 	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
1458 							  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
1459 							  OBJECT_TYPE_CONTEXT );
1460 	if( cryptStatusError( status ) )
1461 		return( status );
1462 	iCryptContext = createInfo.cryptHandle;
1463 	setMessageData( &msgData, "interop interop interop ", 24 );
1464 	status = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE_S,
1465 							  &msgData, CRYPT_CTXINFO_KEY );
1466 	if( cryptStatusError( status ) )
1467 		{
1468 		krnlSendNotifier( iCryptContext, IMESSAGE_DECREFCOUNT );
1469 		return( status );
1470 		}
1471 
1472 	/* Add PKCS #5 padding to the end of the user information and encrypt
1473 	   it */
1474 	REQUIRES( userInfoBufPos + 2 == PKIUSER_ENCR_AUTHENTICATOR_SIZE );
1475 	for( i = 0; i < 2; i++ )
1476 		userInfo[ userInfoBufPos++ ] = 2;
1477 	status = krnlSendNotifier( iCryptContext, IMESSAGE_CTX_GENIV );
1478 	if( cryptStatusOK( status ) )
1479 		status = krnlSendMessage( iCryptContext, IMESSAGE_CTX_ENCRYPT,
1480 								  userInfo, userInfoBufPos );
1481 	if( cryptStatusOK( status ) )
1482 		{
1483 		sMemOpen( &stream, algoID, maxAlgoIdSize );
1484 		status = writeCryptContextAlgoID( &stream, iCryptContext );
1485 		if( cryptStatusOK( status ) )
1486 			*algoIdSize = stell( &stream );
1487 		sMemDisconnect( &stream );
1488 		}
1489 	krnlSendNotifier( iCryptContext, IMESSAGE_DECREFCOUNT );
1490 	if( cryptStatusError( status ) )
1491 		return( status );
1492 	*userInfoSize = userInfoBufPos;
1493 
1494 	return( CRYPT_OK );
1495 	}
1496 
1497 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
writePkiUserInfo(INOUT STREAM * stream,INOUT CERT_INFO * userInfoPtr,STDC_UNUSED const CERT_INFO * issuerCertInfoPtr,STDC_UNUSED const CRYPT_CONTEXT iIssuerCryptContext)1498 static int writePkiUserInfo( INOUT STREAM *stream,
1499 							 INOUT CERT_INFO *userInfoPtr,
1500 							 STDC_UNUSED const CERT_INFO *issuerCertInfoPtr,
1501 							 STDC_UNUSED const CRYPT_CONTEXT iIssuerCryptContext )
1502 	{
1503 	CERT_PKIUSER_INFO *certUserInfo = userInfoPtr->cCertUser;
1504 	BYTE userInfo[ 128 + 8 ], algoID[ 128 + 8 ];
1505 	int certAttributeSize, userAttributeSize = 0, userInfoSize, algoIdSize;
1506 	int length, status;
1507 
1508 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
1509 	assert( isWritePtr( userInfoPtr, sizeof( CERT_INFO ) ) );
1510 
1511 	REQUIRES( issuerCertInfoPtr == NULL );
1512 	REQUIRES( iIssuerCryptContext == CRYPT_UNUSED );
1513 
1514 	if( sIsNullStream( stream ) )
1515 		{
1516 		CRYPT_ATTRIBUTE_TYPE dummy1;
1517 		CRYPT_ERRTYPE_TYPE dummy2;
1518 		MESSAGE_DATA msgData;
1519 		BYTE keyID[ 16 + 8 ];
1520 		int keyIDlength DUMMY_INIT;
1521 
1522 		/* Generate the key identifier.  Once it's in user-encoded form the
1523 		   full identifier can't quite fit so we adjust the size to the
1524 		   maximum amount that we can encode by creating the encoded form
1525 		   (which trims the input to fit) and then decoding it again.  This
1526 		   is necessary because it's also used to locate the user information
1527 		   in a key store, if we used the un-adjusted form for the key ID then
1528 		   we couldn't locate the stored user information using the adjusted
1529 		   form */
1530 		setMessageData( &msgData, keyID, 16 );
1531 		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
1532 								  &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
1533 		if( cryptStatusOK( status ) )
1534 			{
1535 			char encodedKeyID[ 32 + 8 ];
1536 			int encKeyIdSize;
1537 
1538 			status = encodePKIUserValue( encodedKeyID, 32, &encKeyIdSize,
1539 										 keyID, 16, 3 );
1540 			if( cryptStatusOK( status ) )
1541 				status = decodePKIUserValue( keyID, 16, &keyIDlength,
1542 											 encodedKeyID, encKeyIdSize );
1543 			}
1544 		if( cryptStatusError( status ) )
1545 			return( status );
1546 		status = addAttributeFieldString( &userInfoPtr->attributes,
1547 										  CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER,
1548 										  CRYPT_ATTRIBUTE_NONE, keyID,
1549 										  keyIDlength, 0, &dummy1, &dummy2 );
1550 		if( cryptStatusOK( status ) )
1551 			{
1552 			status = checkAttributes( ATTRIBUTE_CERTIFICATE,
1553 									  userInfoPtr->attributes,
1554 									  &userInfoPtr->errorLocus,
1555 									  &userInfoPtr->errorType );
1556 			}
1557 		if( cryptStatusError( status ) )
1558 			return( status );
1559 
1560 		/* We can't generate the user information yet since we're doing the
1561 		   pre-encoding pass and writing to a null stream so we leave it for
1562 		   the actual encoding pass and only provide a size estimate for
1563 		   now */
1564 		userInfoSize = PKIUSER_ENCR_AUTHENTICATOR_SIZE;
1565 
1566 		/* Since we can't use the CAs data storage key yet we set the
1567 		   algorithm ID size to the size of the information for the fixed
1568 		   3DES key */
1569 		algoIdSize = 22;
1570 		}
1571 	else
1572 		{
1573 		status = createPkiUserInfo( certUserInfo, userInfo, 128,
1574 									&userInfoSize, algoID, 128,
1575 									&algoIdSize );
1576 		if( cryptStatusError( status ) )
1577 			return( status );
1578 		}
1579 
1580 	/* Determine the size of the user information */
1581 	status = length = sizeofDN( userInfoPtr->subjectName );
1582 	if( cryptStatusError( status ) )
1583 		return( status );
1584 	userInfoPtr->subjectDNsize = length;
1585 	certAttributeSize = sizeofAttributes( userInfoPtr->attributes,
1586 										  CRYPT_CERTTYPE_PKIUSER );
1587 	if( cryptStatusError( certAttributeSize ) )
1588 		return( certAttributeSize );
1589 	ENSURES( certAttributeSize > 0 && certAttributeSize < MAX_INTLENGTH_SHORT );
1590 	if( certUserInfo->isRA )
1591 		userAttributeSize += sizeofBoolean();
1592 
1593 	/* Write the user DN, encrypted user information, and any supplementary
1594 	   information */
1595 	status = writeDN( stream, userInfoPtr->subjectName, DEFAULT_TAG );
1596 	if( cryptStatusError( status ) )
1597 		return( status );
1598 	swrite( stream, algoID, algoIdSize );
1599 	writeOctetString( stream, userInfo, userInfoSize, DEFAULT_TAG );
1600 	status = writeAttributes( stream, userInfoPtr->attributes,
1601 							  CRYPT_CERTTYPE_PKIUSER, certAttributeSize );
1602 	if( cryptStatusOK( status ) && userAttributeSize > 0 )
1603 		{
1604 		writeSequence( stream, userAttributeSize );
1605 		if( certUserInfo->isRA )
1606 			status = writeBoolean( stream, TRUE, DEFAULT_TAG );
1607 		}
1608 	return( status );
1609 	}
1610 #endif /* USE_PKIUSER */
1611 
1612 /****************************************************************************
1613 *																			*
1614 *						Write Function Access Information					*
1615 *																			*
1616 ****************************************************************************/
1617 
1618 typedef struct {
1619 	const CRYPT_CERTTYPE_TYPE type;
1620 	const WRITECERT_FUNCTION function;
1621 	} CERTWRITE_INFO;
1622 static const CERTWRITE_INFO FAR_BSS certWriteTable[] = {
1623 	{ CRYPT_CERTTYPE_CERTIFICATE, writeCertInfo },
1624 	{ CRYPT_CERTTYPE_CERTCHAIN, writeCertInfo },
1625 	{ CRYPT_CERTTYPE_ATTRIBUTE_CERT, writeAttributeCertInfo },
1626 #ifdef USE_CERTREV
1627 	{ CRYPT_CERTTYPE_CRL, writeCRLInfo },
1628 #endif /* USE_CERTREV */
1629 #ifdef USE_CERTREQ
1630 	{ CRYPT_CERTTYPE_CERTREQUEST, writeCertRequestInfo },
1631 	{ CRYPT_CERTTYPE_REQUEST_CERT, writeCrmfRequestInfo },
1632 	{ CRYPT_CERTTYPE_REQUEST_REVOCATION, writeRevRequestInfo },
1633 #endif /* USE_CERTREQ */
1634 #ifdef USE_CERTVAL
1635 	{ CRYPT_CERTTYPE_RTCS_REQUEST, writeRtcsRequestInfo },
1636 	{ CRYPT_CERTTYPE_RTCS_RESPONSE, writeRtcsResponseInfo },
1637 #endif /* USE_CERTVAL */
1638 #ifdef USE_CERTREV
1639 	{ CRYPT_CERTTYPE_OCSP_REQUEST, writeOcspRequestInfo },
1640 	{ CRYPT_CERTTYPE_OCSP_RESPONSE, writeOcspResponseInfo },
1641 #endif /* USE_CERTREV */
1642 #ifdef USE_CMSATTR
1643 	{ CRYPT_CERTTYPE_CMS_ATTRIBUTES, writeCmsAttributes },
1644 #endif /* USE_CMSATTR */
1645 #ifdef USE_PKIUSER
1646 	{ CRYPT_CERTTYPE_PKIUSER, writePkiUserInfo },
1647 #endif /* USE_PKIUSER */
1648 	{ CRYPT_CERTTYPE_NONE, NULL }, { CRYPT_CERTTYPE_NONE, NULL }
1649 	};
1650 
1651 CHECK_RETVAL_PTR \
getCertWriteFunction(IN_ENUM (CRYPT_CERTTYPE)const CRYPT_CERTTYPE_TYPE certType)1652 WRITECERT_FUNCTION getCertWriteFunction( IN_ENUM( CRYPT_CERTTYPE ) \
1653 											const CRYPT_CERTTYPE_TYPE certType )
1654 	{
1655 	int i;
1656 
1657 	REQUIRES_N( certType > CRYPT_CERTTYPE_NONE && certType < CRYPT_CERTTYPE_LAST );
1658 
1659 	for( i = 0;
1660 		 certWriteTable[ i ].type != CRYPT_CERTTYPE_NONE && \
1661 			i < FAILSAFE_ARRAYSIZE( certWriteTable, CERTWRITE_INFO );
1662 		 i++ )
1663 		{
1664 		if( certWriteTable[ i ].type == certType )
1665 			return( certWriteTable[ i ].function );
1666 		}
1667 	ENSURES_N( i < FAILSAFE_ARRAYSIZE( certWriteTable, CERTWRITE_INFO ) );
1668 
1669 	return( NULL );
1670 	}
1671 #endif /* USE_CERTIFICATES */
1672