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 ¤tTime, 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