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