cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
comp_set.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Set Certificate Components *
4 * Copyright Peter Gutmann 1997-2009 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "cert.h"
10  #include "certattr.h"
11  #include "asn1.h"
12  #include "asn1_ext.h"
13 #else
14  #include "cert/cert.h"
15  #include "cert/certattr.h"
16  #include "enc_dec/asn1.h"
17  #include "enc_dec/asn1_ext.h"
18 #endif /* Compiler-specific includes */
19 
20 #ifdef USE_CERTIFICATES
21 
22 /****************************************************************************
23 * *
24 * Serial-Number Routines *
25 * *
26 ****************************************************************************/
27 
28 /* Set the serial number for a certificate. In theory we could store this
29  as a static value in the configuration database but this has three
30  disadvantages: Updating the serial number updates the entire
31  configuration database (including things the user might not want
32  updated), if the configuration database update fails the serial number
33  never changes, and the predictable serial number allows tracking of the
34  number of certificates that have been issued by the CA. Because of this
35  we just use a 64-bit nonce if the user doesn't supply a value */
36 
38 int setSerialNumber( INOUT CERT_INFO *certInfoPtr,
39  IN_BUFFER_OPT( serialNumberLength ) const void *serialNumber,
41  {
43  BYTE buffer[ 4 + MAX_SERIALNO_SIZE + 8 ];
44  void *serialNumberPtr;
45  int length = DUMMY_INIT, bufPos = 0, status;
46 
47  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
48  assert( ( serialNumber == NULL && serialNumberLength == 0 ) || \
49  ( isReadPtr( serialNumber, serialNumberLength ) ) );
50 
51  REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
52  certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
53  certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN || \
54  certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION );
55  REQUIRES( ( serialNumber == NULL && serialNumberLength == 0 ) || \
56  ( serialNumber != NULL && \
57  serialNumberLength > 0 && \
58  serialNumberLength <= MAX_SERIALNO_SIZE ) );
59 
60  /* Get a pointer to the location where we're going to store the new
61  serial number, either a user-supplied value or one that we've
62  generated ourselves. On the other hand if a serial number has
63  already been set explicitly, don't override it with an implicitly-set
64  one */
65  switch( certInfoPtr->type )
66  {
70  if( certInfoPtr->cCertCert->serialNumber != NULL )
71  {
72  ENSURES( serialNumber == NULL && serialNumberLength == 0 );
73 
74  return( CRYPT_OK );
75  }
76  serialNumberPtr = certInfoPtr->cCertCert->serialNumberBuffer;
77  break;
78 
79 #ifdef USE_CERTREV
81  if( certInfoPtr->cCertReq->serialNumber != NULL )
82  {
83  ENSURES( serialNumber == NULL && serialNumberLength == 0 );
84 
85  return( CRYPT_OK );
86  }
87  serialNumberPtr = certInfoPtr->cCertReq->serialNumberBuffer;
88  break;
89 #endif /* USE_CERTREV */
90 
91  default:
92  retIntError();
93  }
94 
95  /* If we're using user-supplied serial number data, canonicalise it into
96  a form suitable for use as an INTEGER hole */
97  if( serialNumber != NULL )
98  {
99  STREAM stream;
100 
101  sMemOpen( &stream, buffer, 4 + MAX_SERIALNO_SIZE );
102  status = writeInteger( &stream, serialNumber, serialNumberLength,
103  DEFAULT_TAG );
104  if( cryptStatusOK( status ) )
105  length = stell( &stream );
106  sMemDisconnect( &stream );
107  if( cryptStatusError( status ) )
108  return( status );
109  bufPos = 2; /* Skip INTEGER tag + length at the start */
110  length -= 2;
111 
112  /* If it's too long to fit into the certificate's internal serial-
113  number buffer, allocate storage for it dynamically */
114  if( length > SERIALNO_BUFSIZE )
115  {
116  if( ( serialNumberPtr = clDynAlloc( "setSerialNumber",
117  length ) ) == NULL )
118  return( CRYPT_ERROR_MEMORY );
119  }
120  }
121  else
122  {
123  /* Generate a random (but fixed-length) serial number, ensure that
124  the first byte of the value that we use is nonzero (to guarantee
125  a DER encoding), and clear the high bit to provide a constant-
126  length ASN.1 encoded value */
128  "Buffer size" );
130  "Buffer size" );
131  setMessageData( &msgData, buffer, DEFAULT_SERIALNO_SIZE + 1 );
133  IMESSAGE_GETATTRIBUTE_S, &msgData,
134  CRYPT_IATTRIBUTE_RANDOM_NONCE );
135  if( cryptStatusError( status ) )
136  return( status );
137  buffer[ 0 ] &= 0x7F; /* Clear the sign bit */
138  if( buffer[ 0 ] == 0 )
139  {
140  /* The first byte is zero, see if we can use the extra byte of
141  data that we fetched as a nonzero byte. If that's zero too,
142  just set it to 1 */
143  buffer[ 0 ] = intToByte( buffer[ DEFAULT_SERIALNO_SIZE ] & 0x7F );
144  if( buffer[ 0 ] == 0 )
145  buffer[ 0 ] = 1;
146  }
147  length = DEFAULT_SERIALNO_SIZE;
148  }
149 
150  /* Copy across the canonicalised serial number value */
151 #ifdef USE_CERTREV
152  if( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION )
153  {
154  certInfoPtr->cCertReq->serialNumber = serialNumberPtr;
155  certInfoPtr->cCertReq->serialNumberLength = length;
156  }
157  else
158 #endif /* USE_CERTREV */
159  {
160  certInfoPtr->cCertCert->serialNumber = serialNumberPtr;
161  certInfoPtr->cCertCert->serialNumberLength = length;
162  }
163  memcpy( serialNumberPtr, buffer + bufPos, length );
164 
165  return( CRYPT_OK );
166  }
167 
168 /* Compare a serial number in canonical form to a generic serial number,
169  with special handling for leading-zero truncation. This one can get a
170  bit tricky because for a long time Microsoft would fairly consistently
171  encode serial numbers incorrectly so we normalise the values to have no
172  leading zero, which is the lowest common denominator */
173 
174 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
175 BOOLEAN compareSerialNumber( IN_BUFFER( canonSerialNumberLength ) \
176  const void *canonSerialNumber,
178  IN_BUFFER( serialNumberLength ) \
179  const void *serialNumber,
180  IN_LENGTH_SHORT const int serialNumberLength )
181  {
182  const BYTE *canonSerialNumberPtr = canonSerialNumber;
183  const BYTE *serialNumberPtr = serialNumber;
184  int canonSerialLength = canonSerialNumberLength;
185  int serialLength;
186 
187  assert( isReadPtr( canonSerialNumber, canonSerialNumberLength ) );
188  assert( isReadPtr( serialNumber, serialNumberLength ) );
189 
190  REQUIRES( canonSerialNumberLength > 0 && \
191  canonSerialNumberLength < MAX_INTLENGTH_SHORT );
192  REQUIRES( serialNumberLength > 0 && \
193  serialNumberLength < MAX_INTLENGTH_SHORT );
194 
195  /* Internal serial numbers are canonicalised so all we need to do is
196  strip a possible leading zero */
197  if( canonSerialNumberPtr[ 0 ] == 0 )
198  {
199  canonSerialNumberPtr++;
200  canonSerialLength--;
201  }
202  ENSURES( canonSerialLength == 0 || canonSerialNumberPtr[ 0 ] != 0 );
203 
204  /* Serial numbers from external sources can be arbitarily strangely
205  encoded so we strip leading zeroes until we get to actual data */
206  for( serialLength = serialNumberLength;
207  serialLength > 0 && serialNumberPtr[ 0 ] == 0;
208  serialLength--, serialNumberPtr++ );
209 
210  /* Finally we've got them in a form where we can compare them */
211  if( canonSerialLength != serialLength )
212  return( FALSE );
213  if( canonSerialLength == 0 )
214  {
215  /* It's an all-zeroes serialNumber, there's nothing to compare */
216  return( TRUE );
217  }
218  return( memcmp( canonSerialNumberPtr, serialNumberPtr,
219  serialLength ) ? FALSE : TRUE );
220  }
221 
222 /****************************************************************************
223 * *
224 * Set Miscellaneous Information *
225 * *
226 ****************************************************************************/
227 
228 /* Set XYZZY certificate information */
229 
231 static int setXyzzyInfo( INOUT CERT_INFO *certInfoPtr )
232  {
234  const int keyUsage = KEYUSAGE_SIGN | KEYUSAGE_CA | \
235  CRYPT_KEYUSAGE_KEYENCIPHERMENT;
236  const time_t currentTime = getApproxTime();
237  int status;
238 
239  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
240 
241  REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
242  certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
243  certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
244 
245  /* Make sure that we haven't already set up this certificate as a XYZZY
246  certificate */
247  attributePtr = findAttributeField( certInfoPtr->attributes,
250  if( attributePtr != NULL )
251  {
252  void *policyOidPtr;
253  int policyOidLength;
254 
255  status = getAttributeDataPtr( attributePtr, &policyOidPtr,
256  &policyOidLength );
257  if( cryptStatusOK( status ) && \
258  policyOidLength == sizeofOID( OID_CRYPTLIB_XYZZYCERT ) && \
259  !memcmp( policyOidPtr, OID_CRYPTLIB_XYZZYCERT,
261  {
262  setErrorInfo( certInfoPtr, CRYPT_CERTINFO_XYZZY,
264  return( CRYPT_ERROR_INITED );
265  }
266  }
267 
268  /* Clear any existing attribute values before trying to set new ones.
269  We don't check the return values for these operations because
270  depending on whether a component is present or not we could get a
271  success or error status, and in any case any problem with deleting
272  a present component will be caught when we try and set the new value
273  further on */
274  certInfoPtr->startTime = certInfoPtr->endTime = 0;
275  ( void ) deleteCertComponent( certInfoPtr, CRYPT_CERTINFO_KEYUSAGE );
276  ( void ) deleteCertComponent( certInfoPtr,
278 
279  /* Give the certificate a 20-year expiry time, make it a self-signed CA
280  certificate with all key usage types enabled, and set the policy OID
281  to identify it as a XYZZY certificate */
282  certInfoPtr->startTime = currentTime;
283  certInfoPtr->endTime = certInfoPtr->startTime + ( 86400L * 365 * 20 );
284  certInfoPtr->flags |= CERT_FLAG_SELFSIGNED;
285  status = addCertComponent( certInfoPtr, CRYPT_CERTINFO_CA, TRUE );
286  if( cryptStatusOK( status ) )
287  status = addCertComponent( certInfoPtr, CRYPT_CERTINFO_KEYUSAGE,
288  keyUsage );
289  if( cryptStatusOK( status ) )
290  status = addCertComponentString( certInfoPtr,
294  if( cryptStatusOK( status ) )
295  {
296  attributePtr = findAttributeFieldEx( certInfoPtr->attributes,
298  ENSURES( attributePtr != NULL );
299  setAttributeProperty( attributePtr, ATTRIBUTE_PROPERTY_LOCKED, 0 );
300  }
301  return( status );
302  }
303 
304 #ifdef USE_CERT_DNSTRING
305 
306 /* Convert a DN in string form into a certificate DN */
307 
308 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
309 static int getEncodedDn( INOUT CERT_INFO *certInfoPtr,
310  IN_BUFFER( dnStringLength ) const void *dnString,
311  IN_LENGTH_ATTRIBUTE const int dnStringLength )
312  {
313  SELECTION_STATE savedState;
314  int status;
315 
316  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
317  assert( isReadPtr( dnString, dnStringLength ) );
318 
319  REQUIRES( dnStringLength > 0 && dnStringLength < MAX_INTLENGTH_SHORT );
320 
321  /* If there's already a DN set then we can't do anything else. Since
322  this potentially changes the DN selection state, we save the state
323  around the check */
324  saveSelectionState( savedState, certInfoPtr );
325  status = selectDN( certInfoPtr, CRYPT_ATTRIBUTE_NONE, MUST_BE_PRESENT );
326  if( cryptStatusOK( status ) && \
327  *certInfoPtr->currentSelection.dnPtr == NULL )
328  {
329  /* There's a DN selected but it's empty (in other words it's been
330  marked for create-on-access but doesn't actually exist yet),
331  we're OK */
332  status = CRYPT_ERROR;
333  }
334  restoreSelectionState( savedState, certInfoPtr );
335  if( cryptStatusOK( status ) )
336  return( CRYPT_ERROR_INITED );
337 
338  /* Read the entire DN from its string form into the selected DN */
339  status = selectDN( certInfoPtr, CRYPT_ATTRIBUTE_NONE, CREATE_IF_ABSENT );
340  if( cryptStatusError( status ) )
341  return( status );
342  status = readDNstring( certInfoPtr->currentSelection.dnPtr,
343  dnString, dnStringLength );
344  if( cryptStatusOK( status ) && \
345  certInfoPtr->currentSelection.updateCursor )
346  {
347  /* If we couldn't update the cursor earlier on because the attribute
348  field in question hadn't been created yet, do it now. Since this
349  is merely a side-effect of the DN-read operation we ignore the
350  return status and return the main result status */
351  ( void ) selectGeneralName( certInfoPtr,
352  certInfoPtr->currentSelection.generalName,
353  MAY_BE_ABSENT );
354  }
355  return( status );
356  }
357 #endif /* USE_CERT_DNSTRING */
358 
359 /****************************************************************************
360 * *
361 * Add a Component *
362 * *
363 ****************************************************************************/
364 
365 /* Add a certificate component */
366 
368 int addCertComponent( INOUT CERT_INFO *certInfoPtr,
370  IN_INT_Z const int certInfo )
371  {
373  int status;
374 
375  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
376 
377  REQUIRES( isAttribute( certInfoType ) || \
378  isInternalAttribute( certInfoType ) );
379 
380  /* If we're adding data to a certificate, clear the error information */
381  if( !isPseudoInformation( certInfoType ) )
382  clearErrorInfo( certInfoPtr );
383 
384  /* If it's a GeneralName or DN selection component, add it. These are
385  special-case attribute values so they have to come before the
386  attribute-handling code */
387  if( isGeneralNameSelectionComponent( certInfoType ) )
388  {
389  status = selectGeneralName( certInfoPtr, certInfoType,
390  MAY_BE_ABSENT );
391  if( cryptStatusError( status ) )
392  return( status );
393  return( selectGeneralName( certInfoPtr, CRYPT_ATTRIBUTE_NONE,
394  MUST_BE_PRESENT ) );
395  }
396 
397  /* If it's standard certificate or CMS attribute, add it to the
398  certificate */
399  if( ( certInfoType >= CRYPT_CERTINFO_FIRST_EXTENSION && \
400  certInfoType <= CRYPT_CERTINFO_LAST_EXTENSION ) || \
401  ( certInfoType >= CRYPT_CERTINFO_FIRST_CMS && \
402  certInfoType <= CRYPT_CERTINFO_LAST_CMS ) )
403  {
404  int localCertInfoType = certInfoType;
405 
406  /* Revocation reason codes are actually a single range of values
407  spread across two different extensions so we adjust the
408  (internal) type based on the reason code value */
409  if( certInfoType == CRYPT_CERTINFO_CRLREASON || \
410  certInfoType == CRYPT_CERTINFO_CRLEXTREASON )
411  {
412  localCertInfoType = ( certInfo < CRYPT_CRLREASON_LAST ) ? \
414  }
415 
416  /* If it's a CRL, RTCS, or OCSP per-entry attribute, add the
417  attribute to the currently selected entry unless it's a
418  revocation request, in which case it goes in with the main
419  attributes */
420 #if defined( USE_CERTREV ) || defined( USE_CERTVAL )
421  if( isRevocationEntryComponent( localCertInfoType ) && \
423  {
424  #ifdef USE_CERTVAL
425  if( certInfoPtr->type == CRYPT_CERTTYPE_RTCS_REQUEST || \
426  certInfoPtr->type == CRYPT_CERTTYPE_RTCS_RESPONSE )
427  {
428  if( certInfoPtr->cCertVal->currentValidity == NULL )
429  return( CRYPT_ERROR_NOTFOUND );
430  return( addAttributeField( \
431  &certInfoPtr->cCertVal->currentValidity->attributes,
432  localCertInfoType, CRYPT_ATTRIBUTE_NONE,
433  certInfo, ATTR_FLAG_NONE, &certInfoPtr->errorLocus,
434  &certInfoPtr->errorType ) );
435  }
436  #endif /* USE_CERTVAL */
437  #ifdef USE_CERTREV
438  ENSURES( certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
439  certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST || \
440  certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE );
441 
442  if( certInfoPtr->cCertRev->currentRevocation == NULL )
443  return( CRYPT_ERROR_NOTFOUND );
444  return( addAttributeField( \
445  &certInfoPtr->cCertRev->currentRevocation->attributes,
446  localCertInfoType, CRYPT_ATTRIBUTE_NONE,
447  certInfo, ATTR_FLAG_NONE, &certInfoPtr->errorLocus,
448  &certInfoPtr->errorType ) );
449  #endif /* USE_CERTREV */
450  }
451 #endif /* USE_CERTREV || USE_CERTVAL */
452 
453  return( addAttributeField( &certInfoPtr->attributes,
454  localCertInfoType, CRYPT_ATTRIBUTE_NONE, certInfo,
455  ATTR_FLAG_NONE, &certInfoPtr->errorLocus,
456  &certInfoPtr->errorType ) );
457  }
458 
459  /* If it's anything else, handle it specially */
460  switch( certInfoType )
461  {
463  if( certInfo )
464  certInfoPtr->flags |= CERT_FLAG_SELFSIGNED;
465  else
466  certInfoPtr->flags &= ~CERT_FLAG_SELFSIGNED;
467  return( CRYPT_OK );
468 
470  return( setXyzzyInfo( certInfoPtr ) );
471 
473  return( setCertificateCursor( certInfoPtr, certInfo ) );
474 
478  return( setAttributeCursor( certInfoPtr, certInfoType, certInfo ) );
479 
481  certInfoPtr->cCertCert->trustedUsage = certInfo;
482  return( CRYPT_OK );
483 
485  {
486  int value;
487 
488  /* This option is only valid for CA certificates */
489  status = getAttributeFieldValue( certInfoPtr->attributes,
491  CRYPT_ATTRIBUTE_NONE, &value );
492  if( cryptStatusError( status ) || !( value & KEYUSAGE_CA ) )
493  {
494  setErrorInfo( certInfoPtr, CRYPT_CERTINFO_CA,
496  return( CRYPT_ARGERROR_NUM1 );
497  }
498  return( krnlSendMessage( certInfoPtr->ownerHandle,
500  &certInfoPtr->objectHandle,
501  certInfo ? MESSAGE_TRUSTMGMT_ADD : \
503  }
504 
505 #ifdef USE_CERTREV
507  certInfoPtr->cCertRev->signatureLevel = certInfo;
508  return( CRYPT_OK );
509 #endif /* USE_CERTREV */
510 
512  certInfoPtr->version = certInfo;
513  return( CRYPT_OK );
514 
516  return( copyPublicKeyInfo( certInfoPtr, certInfo, NULL ) );
517 
519  /* If it's a certificate, copy across various components or
520  store the entire certificate where required */
521  status = krnlSendMessage( certInfo, IMESSAGE_GETDEPENDENT,
522  &addedCert, OBJECT_TYPE_CERTIFICATE );
523  if( cryptStatusError( status ) )
524  return( status );
525 
526  /* If it's a certificate chain then we're adding the complete
527  certificate, just store it and exit */
528  if( certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN )
529  {
530  CERT_CERT_INFO *certCertInfoPtr = certInfoPtr->cCertCert;
531  int i;
532 
533  if( certCertInfoPtr->chainEnd >= MAX_CHAINLENGTH - 1 )
534  return( CRYPT_ERROR_OVERFLOW );
535 
536  /* Perform a simple check to make sure that it hasn't been
537  added already */
538  for( i = 0; i < certCertInfoPtr->chainEnd && \
539  i < MAX_CHAINLENGTH; i++ )
540  {
541  if( cryptStatusOK( \
542  krnlSendMessage( addedCert, IMESSAGE_COMPARE,
543  &certCertInfoPtr->chain[ i ],
545  {
546  setErrorInfo( certInfoPtr,
549  return( CRYPT_ERROR_INITED );
550  }
551  }
552  ENSURES( i < MAX_CHAINLENGTH );
553 
554  /* Add the user certificate and increment its reference
555  count */
557  certCertInfoPtr->chain[ certCertInfoPtr->chainEnd++ ] = addedCert;
558 
559  return( CRYPT_OK );
560  }
561 
562  /* For the remaining operations we need access to the user
563  certificate internals */
564  return( copyCertObject( certInfoPtr, addedCert,
565  CRYPT_CERTINFO_CERTIFICATE, certInfo ) );
566 
568  /* We can't add another CA certificate if there's already one
569  present, in theory this is valid but it's more likely to be
570  an implementation problem than an attempt to query multiple
571  CAs through a single responder */
572  if( certInfoPtr->certHashSet )
573  {
576  return( CRYPT_ERROR_INITED );
577  }
578  ENSURES( certInfoPtr->version == 1 );
579 
580  /* Get the certificate handle and make sure that it really is a
581  CA certificate */
582  status = krnlSendMessage( certInfo, IMESSAGE_GETDEPENDENT,
583  &addedCert, OBJECT_TYPE_CERTIFICATE );
584  if( cryptStatusError( status ) )
585  return( status );
586  if( cryptStatusError( \
587  krnlSendMessage( addedCert, IMESSAGE_CHECK, NULL,
588  MESSAGE_CHECK_CA ) ) )
589  return( CRYPT_ARGERROR_NUM1 );
590 
591  return( copyCertObject( certInfoPtr, addedCert,
593 
594 #ifdef USE_CERTREQ
596  /* Make sure that we haven't already got a public key (either as
597  a context or encoded key data) or DN present */
598  if( ( certInfoPtr->iPubkeyContext != CRYPT_ERROR || \
599  certInfoPtr->publicKeyInfo != NULL ) || \
600  certInfoPtr->subjectName != NULL )
601  {
604  return( CRYPT_ERROR_INITED );
605  }
606 
607  return( copyCertObject( certInfoPtr, certInfo,
609 #endif /* USE_CERTREQ */
610 
611  case CRYPT_IATTRIBUTE_CERTCOLLECTION:
612  return( copyCertChain( certInfoPtr, certInfo, TRUE ) );
613 
614  case CRYPT_IATTRIBUTE_RTCSREQUEST:
615  case CRYPT_IATTRIBUTE_OCSPREQUEST:
616  case CRYPT_IATTRIBUTE_REVREQUEST:
617  case CRYPT_IATTRIBUTE_PKIUSERINFO:
618  case CRYPT_IATTRIBUTE_BLOCKEDATTRS:
619  return( copyCertObject( certInfoPtr, certInfo, certInfoType,
620  CRYPT_UNUSED ) );
621  }
622 
623  retIntError();
624  }
625 
626 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
627 int addCertComponentString( INOUT CERT_INFO *certInfoPtr,
628  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE certInfoType,
629  IN_BUFFER( certInfoLength ) const void *certInfo,
630  IN_LENGTH_SHORT const int certInfoLength )
631  {
632  int status;
633 
634  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
635  assert( isReadPtr( certInfo, certInfoLength ) );
636 
637  REQUIRES( isAttribute( certInfoType ) || \
638  isInternalAttribute( certInfoType ) );
639  REQUIRES( certInfoLength > 0 && certInfoLength < MAX_INTLENGTH_SHORT );
640 
641  /* If we're adding data to a certificate, clear the error information */
642  if( !isPseudoInformation( certInfoType ) )
643  clearErrorInfo( certInfoPtr );
644 
645  /* If it's a GeneralName or DN component, add it. These are special-
646  case attribute values so they have to come before the attribute-
647  handling code */
648  if( isGeneralNameComponent( certInfoType ) )
649  {
651 
652  status = selectGeneralName( certInfoPtr, CRYPT_ATTRIBUTE_NONE,
654  if( cryptStatusError( status ) )
655  return( status );
656  if( certInfoPtr->attributeCursor != NULL )
657  {
658  status = getAttributeIdInfo( certInfoPtr->attributeCursor, NULL,
659  &fieldID, NULL );
660  if( cryptStatusError( status ) )
661  return( status );
662  }
663  else
664  fieldID = certInfoPtr->currentSelection.generalName;
665  status = addAttributeFieldString( &certInfoPtr->attributes,
666  fieldID, certInfoType, certInfo, certInfoLength,
667  ATTR_FLAG_NONE, &certInfoPtr->errorLocus,
668  &certInfoPtr->errorType );
669  if( cryptStatusError( status ) )
670  return( status );
671  if( certInfoPtr->currentSelection.updateCursor )
672  {
673  /* If we couldn't update the cursor earlier on because the
674  attribute field in question hadn't been created yet, do it
675  now. Since this is merely a side-effect of this operation,
676  we ignore the return status and return the main result
677  status */
678  ( void ) selectGeneralName( certInfoPtr,
679  certInfoPtr->currentSelection.generalName,
680  MAY_BE_ABSENT );
681  }
682  return( CRYPT_OK );
683  }
684  if( isDNComponent( certInfoType ) )
685  {
686  /* Add the string component to the DN */
687  status = selectDN( certInfoPtr, CRYPT_ATTRIBUTE_NONE,
689  if( cryptStatusError( status ) )
690  {
691  certInfoPtr->errorLocus = certInfoType;
692  return( status );
693  }
694  status = insertDNComponent( certInfoPtr->currentSelection.dnPtr,
695  certInfoType, certInfo,
696  certInfoLength, &certInfoPtr->errorType );
697  if( cryptStatusOK( status ) && \
698  certInfoPtr->currentSelection.updateCursor )
699  {
700  /* If we couldn't update the cursor earlier on because the
701  attribute field in question hadn't been created yet, do it
702  now. Since this is merely a side-effect of this operation,
703  we ignore the return status and return the main result
704  status */
705  ( void ) selectGeneralName( certInfoPtr,
706  certInfoPtr->currentSelection.generalName,
707  MAY_BE_ABSENT );
708  }
709  if( cryptStatusError( status ) && status != CRYPT_ERROR_MEMORY )
710  certInfoPtr->errorLocus = certInfoType;
711  return( status );
712  }
713 
714  /* If it's standard certificate or CMS attribute, add it to the
715  certificate */
716  if( ( certInfoType >= CRYPT_CERTINFO_FIRST_EXTENSION && \
717  certInfoType <= CRYPT_CERTINFO_LAST_EXTENSION ) || \
718  ( certInfoType >= CRYPT_CERTINFO_FIRST_CMS && \
719  certInfoType <= CRYPT_CERTINFO_LAST_CMS ) )
720  {
721  int localCertInfoType = certInfoType;
722 
723  /* If it's a CRL, RTCS, or OCSP per-entry attribute, add the
724  attribute to the currently selected entry unless it's a
725  revocation request, in which case it goes in with the main
726  attributes */
727 #if defined( USE_CERTREV ) || defined( USE_CERTVAL )
728  if( isRevocationEntryComponent( localCertInfoType ) && \
730  {
731  #ifdef USE_CERTVAL
732  if( certInfoPtr->type == CRYPT_CERTTYPE_RTCS_REQUEST || \
733  certInfoPtr->type == CRYPT_CERTTYPE_RTCS_RESPONSE )
734  {
735  if( certInfoPtr->cCertVal->currentValidity == NULL )
736  return( CRYPT_ERROR_NOTFOUND );
737  return( addAttributeFieldString( \
738  &certInfoPtr->cCertVal->currentValidity->attributes,
739  localCertInfoType, CRYPT_ATTRIBUTE_NONE,
740  certInfo, certInfoLength, ATTR_FLAG_NONE,
741  &certInfoPtr->errorLocus, &certInfoPtr->errorType ) );
742  }
743  #endif /* USE_CERTVAL */
744  #ifdef USE_CERTREV
745  ENSURES( certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
746  certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST || \
747  certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE );
748 
749  if( certInfoPtr->cCertRev->currentRevocation == NULL )
750  return( CRYPT_ERROR_NOTFOUND );
751  return( addAttributeFieldString( \
752  &certInfoPtr->cCertRev->currentRevocation->attributes,
753  localCertInfoType, CRYPT_ATTRIBUTE_NONE,
754  certInfo, certInfoLength, ATTR_FLAG_NONE,
755  &certInfoPtr->errorLocus, &certInfoPtr->errorType ) );
756  #endif /* USE_CERTREV */
757  }
758 #endif /* USE_CERTREV || USE_CERTVAL */
759 
760  return( addAttributeFieldString( &certInfoPtr->attributes,
761  localCertInfoType, CRYPT_ATTRIBUTE_NONE, certInfo,
762  certInfoLength, ATTR_FLAG_NONE,
763  &certInfoPtr->errorLocus, &certInfoPtr->errorType ) );
764  }
765 
766  /* If it's anything else, handle it specially */
767  switch( certInfoType )
768  {
770  ENSURES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE );
771  if( certInfoPtr->cCertCert->serialNumber != NULL )
772  {
775  return( CRYPT_ERROR_INITED );
776  }
777  return( setSerialNumber( certInfoPtr, certInfo,
778  certInfoLength ) );
779 
782  {
783  time_t certTime = *( ( time_t * ) certInfo );
784 
785  if( certInfoPtr->startTime > 0 )
786  {
787  setErrorInfo( certInfoPtr, certInfoType,
789  return( CRYPT_ERROR_INITED );
790  }
791  if( certInfoPtr->endTime > 0 && \
792  certTime >= certInfoPtr->endTime )
793  {
794  setErrorInfo( certInfoPtr,
795  ( certInfoType == CRYPT_CERTINFO_VALIDFROM ) ? \
798  return( CRYPT_ARGERROR_STR1 );
799  }
800  certInfoPtr->startTime = certTime;
801  return( CRYPT_OK );
802  }
803 
806  {
807  time_t certTime = *( ( time_t * ) certInfo );
808 
809  if( certInfoPtr->endTime > 0 )
810  {
811  setErrorInfo( certInfoPtr, certInfoType,
813  return( CRYPT_ERROR_INITED );
814  }
815  if( certInfoPtr->startTime > 0 && \
816  certTime <= certInfoPtr->startTime )
817  {
818  setErrorInfo( certInfoPtr,
819  ( certInfoType == CRYPT_CERTINFO_VALIDTO ) ? \
822  return( CRYPT_ARGERROR_STR1 );
823  }
824  certInfoPtr->endTime = certTime;
825  return( CRYPT_OK );
826  }
827 
828 #ifdef USE_CERTREV
830  {
831  time_t certTime = *( ( time_t * ) certInfo );
832  time_t *revocationTimePtr = getRevocationTimePtr( certInfoPtr );
833 
834  if( *revocationTimePtr > 0 )
835  {
836  setErrorInfo( certInfoPtr, certInfoType,
838  return( CRYPT_ERROR_INITED );
839  }
840  *revocationTimePtr = certTime;
841  return( CRYPT_OK );
842  }
843 #endif /* USE_CERTREV */
844 
845 #ifdef USE_CERT_DNSTRING
846  case CRYPT_CERTINFO_DN:
847  return( getEncodedDn( certInfoPtr, certInfo, certInfoLength ) );
848 #endif /* USE_CERT_DNSTRING */
849 
850 #ifdef USE_CERTREV
851  case CRYPT_IATTRIBUTE_CRLENTRY:
852  {
853  STREAM stream;
854 
855  ENSURES( certInfoPtr->type == CRYPT_CERTTYPE_CRL );
856 
857  /* The revocation information is being provided to us in pre-
858  encoded form from a certificate store, decode it so that we
859  can add it to the CRL */
860  sMemConnect( &stream, certInfo, certInfoLength );
861  status = readCRLentry( &stream,
862  &certInfoPtr->cCertRev->revocations, 0,
863  &certInfoPtr->errorLocus,
864  &certInfoPtr->errorType );
865  sMemDisconnect( &stream );
866  return( status );
867  }
868 #endif /* USE_CERTREV */
869 
870 #ifdef USE_CERTREQ
871  case CRYPT_IATTRIBUTE_AUTHCERTID:
872  ENSURES( certInfoLength == KEYID_SIZE );
873  memcpy( certInfoPtr->cCertReq->authCertID, certInfo, KEYID_SIZE );
874  return( CRYPT_OK );
875 #endif /* USE_CERTREQ */
876  }
877 
878  retIntError();
879  }
880 #endif /* USE_CERTIFICATES */