cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
cryptcrt.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib Certificate Management Routines *
4 * Copyright Peter Gutmann 1996-2008 *
5 * *
6 ****************************************************************************/
7 
8 /* "By the power vested in me, I now declare this text string and this bit
9  string 'name' and 'key'. What RSA has joined, let no man put asunder".
10  -- Bob Blakley */
11 #include <ctype.h>
12 #include "crypt.h"
13 #ifdef INC_ALL
14  #include "cert.h"
15  #include "asn1.h"
16 #else
17  #include "cert/cert.h"
18  #include "enc_dec/asn1.h"
19 #endif /* Compiler-specific includes */
20 
21 /* The minimum size for an OBJECT IDENTIFIER expressed as ASCII characters */
22 
23 #define MIN_ASCII_OIDSIZE 7
24 
25 #ifdef USE_CERTIFICATES
26 
27 /****************************************************************************
28 * *
29 * Utility Functions *
30 * *
31 ****************************************************************************/
32 
33 /* Compare values to data in a certificate */
34 
36 static BOOLEAN compareCertInfo( const CERT_INFO *certInfoPtr,
38  const MESSAGE_COMPARE_TYPE compareType,
39  IN_BUFFER_OPT( dataLength ) const void *data,
40  IN_LENGTH_SHORT_Z const int dataLength,
42  {
43  int status;
44 
45  assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
46  assert( ( data == NULL && dataLength == 0 ) || \
47  isReadPtr( data, dataLength ) );
48 
49  REQUIRES_B( compareType > MESSAGE_COMPARE_NONE && \
50  compareType < MESSAGE_COMPARE_LAST );
51  REQUIRES_B( ( compareType == MESSAGE_COMPARE_CERTOBJ && \
52  data == NULL && dataLength == 0 && \
53  isHandleRangeValid( iCryptCert ) ) || \
54  ( compareType != MESSAGE_COMPARE_CERTOBJ && \
55  data != NULL && \
56  dataLength > 0 && dataLength < MAX_INTLENGTH_SHORT && \
57  iCryptCert == CRYPT_UNUSED ) );
58 
59  switch( compareType )
60  {
62  if( dataLength != certInfoPtr->subjectDNsize || \
63  memcmp( data, certInfoPtr->subjectDNptr,
64  certInfoPtr->subjectDNsize ) )
65  return( FALSE );
66  return( TRUE );
67 
69  {
70  STREAM stream;
71  void *dataPtr = DUMMY_INIT_PTR;
72  int dataLeft = DUMMY_INIT, serialNoLength, length;
73 
74  if( certInfoPtr->type != CRYPT_CERTTYPE_CERTIFICATE && \
75  certInfoPtr->type != CRYPT_CERTTYPE_CERTCHAIN )
76  return( FALSE );
77 
78  /* Comparing an iAndS can get quite tricky because of assorted
79  braindamage in encoding methods so that two dissimilar
80  iAndSs aren't necessarily supposed to be regarded as non-
81  equal. First we try a trivial reject check, if that passes
82  we compare the issuerName and serialNumber with corrections
83  for common encoding braindamage. Note that even this
84  comparison can fail since older versions of the Entegrity
85  toolkit (from the early 1990s) rewrote T61Strings in
86  certificates as PrintableStrings in recipientInfo which means
87  that any kind of straight comparison on these would fail. We
88  don't bother handling this sort of thing, and it's likely
89  that most other software won't either (this situation only
90  occurs when a certificate issuerName contains PrintableString
91  text incorrectly encoded as T61String, which is rare enough
92  that it required artifically-created certificates just to
93  reproduce the problem). In addition the trivial reject check
94  can also fail since in an extreme encoding braindamage case a
95  BMPString rewritten as a PrintableString would experience a
96  large enough change in length to fail the check, but as with
97  the Entegrity problem this is a level of brokenness up with
98  which we will not put */
99  length = ( int ) sizeofObject( \
100  certInfoPtr->issuerDNsize + \
101  sizeofObject( certInfoPtr->cCertCert->serialNumberLength ) );
102  if( length < dataLength - 2 || length > dataLength + 2 )
103  {
104  /* Trivial reject, the lengths are too dissimilar for any
105  fixup attempts to work */
106  return( FALSE );
107  }
108 
109  /* We also disallow obviously-invalid lengths at this point to
110  ensure that we don't try and do anything with invalid data */
111  if( length < 16 || length > MAX_INTLENGTH_SHORT || \
112  dataLength < 16 || dataLength > MAX_INTLENGTH_SHORT )
113  return( FALSE );
114 
115  /* We got past the trivial reject check, try a more detailed check,
116  first the issuerName */
117  sMemConnect( &stream, data, dataLength );
118  status = readSequence( &stream, NULL );
119  if( cryptStatusOK( status ) )
120  {
121  dataLeft = dataLength - stell( &stream );
122  status = sMemGetDataBlock( &stream, &dataPtr, dataLeft );
123  }
124  if( cryptStatusOK( status ) )
125  status = getObjectLength( dataPtr, dataLeft, &length );
126  if( cryptStatusOK( status ) )
127  status = readUniversal( &stream );
128  if( cryptStatusError( status ) )
129  {
130  sMemDisconnect( &stream );
131  return( FALSE );
132  }
133  ANALYSER_HINT( dataPtr != NULL );
134  if( length != certInfoPtr->issuerDNsize || \
135  memcmp( dataPtr, certInfoPtr->issuerDNptr,
136  certInfoPtr->issuerDNsize ) )
137  {
138  sMemDisconnect( &stream );
139  return( FALSE );
140  }
141 
142  /* Compare the serialNumber */
143  status = readGenericHole( &stream, &serialNoLength, 1,
144  BER_INTEGER );
145  if( cryptStatusOK( status ) )
146  {
147  dataLeft = dataLength - stell( &stream );
148  status = sMemGetDataBlock( &stream, &dataPtr, dataLeft );
149  }
150  if( cryptStatusOK( status ) )
151  status = sSkip( &stream, serialNoLength );
152  sMemDisconnect( &stream );
153  if( cryptStatusError( status ) )
154  return( FALSE );
155  if( !compareSerialNumber( certInfoPtr->cCertCert->serialNumber,
156  certInfoPtr->cCertCert->serialNumberLength,
157  dataPtr, serialNoLength ) )
158  return( FALSE );
159 
160  return( TRUE );
161  }
162 
167  {
168  static const MAP_TABLE fingerprintMapTable[] = {
173  { CRYPT_ERROR, 0 }, { CRYPT_ERROR, 0 }
174  };
176  BYTE fingerPrint[ CRYPT_MAX_HASHSIZE + 8 ];
177  int fingerPrintLength, attributeToCompare;
178 
179  status = mapValue( compareType, &attributeToCompare,
180  fingerprintMapTable,
181  FAILSAFE_ARRAYSIZE( fingerprintMapTable, \
182  MAP_TABLE ) );
183  ENSURES( cryptStatusOK( status ) );
184 
185  /* If the certificate hasn't been signed yet we can't compare
186  the fingerprint */
187  if( certInfoPtr->certificate == NULL )
188  return( FALSE );
189 
190  /* Get the certificate fingerprint and compare it to what we've
191  been given */
192  status = getCertComponentString( ( CERT_INFO * ) certInfoPtr,
193  attributeToCompare, fingerPrint,
195  &fingerPrintLength );
196  if( cryptStatusError( status ) )
197  return( FALSE );
198 
199  /* If it's a straight fingerprint compare, compare the
200  certificate fingerprint to the user-supplied value */
201  if( compareType != MESSAGE_COMPARE_CERTOBJ )
202  {
203  return( ( dataLength == fingerPrintLength && \
204  !memcmp( data, fingerPrint, fingerPrintLength ) ) ? \
205  TRUE : FALSE );
206  }
207 
208  /* It's a full certificate compare, compare the encoded
209  certificate data via the fingerprints */
210  setMessageData( &msgData, fingerPrint, fingerPrintLength );
211  status = krnlSendMessage( iCryptCert, IMESSAGE_COMPARE, &msgData,
213  return( cryptStatusOK( status ) ? TRUE : FALSE );
214  }
215  }
216 
218  }
219 
220 /* Check the usage of a certificate against a MESSAGE_CHECK_TYPE check */
221 
223 static int checkCertUsage( INOUT CERT_INFO *certInfoPtr,
225  const MESSAGE_CHECK_TYPE checkType )
226  {
227  int complianceLevel, keyUsageValue, checkKeyFlag = CHECKKEY_FLAG_NONE;
228  int status;
229 
230  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
231 
232  REQUIRES( checkType > MESSAGE_CHECK_NONE && \
233  checkType < MESSAGE_CHECK_LAST );
234 
235  /* Map the check type to a key usage that we check for */
236  switch( checkType )
237  {
239  /* This check type can be encountered when checking a private
240  key with a certificate attached */
241  keyUsageValue = CRYPT_KEYUSAGE_NONE;
242  checkKeyFlag = CHECKKEY_FLAG_PRIVATEKEY;
243  break;
244 
247  keyUsageValue = CRYPT_KEYUSAGE_KEYENCIPHERMENT;
248  break;
249 
252  keyUsageValue = CRYPT_KEYUSAGE_KEYENCIPHERMENT;
253  checkKeyFlag = CHECKKEY_FLAG_PRIVATEKEY;
254  break;
255 
258  keyUsageValue = KEYUSAGE_SIGN | KEYUSAGE_CA;
259  checkKeyFlag = CHECKKEY_FLAG_PRIVATEKEY;
260  break;
261 
264  keyUsageValue = KEYUSAGE_SIGN | KEYUSAGE_CA;
265  break;
266 
269  /* exportOnly usage falls back to plain keyAgreement if
270  necessary */
271  keyUsageValue = CRYPT_KEYUSAGE_KEYAGREEMENT | \
272  CRYPT_KEYUSAGE_ENCIPHERONLY;
273  break;
274 
277  /* importOnly usage falls back to plain keyAgreement if
278  necessary */
279  keyUsageValue = CRYPT_KEYUSAGE_KEYAGREEMENT | \
280  CRYPT_KEYUSAGE_DECIPHERONLY;
281  break;
282 
283  case MESSAGE_CHECK_CA:
285  /* A special-case version of MESSAGE_CHECK_PKC_SIGN/
286  MESSAGE_CHECK_PKC_SIGCHECK that applies only to
287  certificates */
288  keyUsageValue = KEYUSAGE_CA;
289  checkKeyFlag = CHECKKEY_FLAG_CA;
290  break;
291 
292  case MESSAGE_CHECK_PKC:
293  /* If we're just checking for generic PKC functionality then
294  any kind of usage is OK */
295  return( CRYPT_OK );
296 
298  /* A generic check for certificate validity that doesn't require
299  full certificate processing as a MESSAGE_CRT_SIGCHECK would,
300  used when there's no signing certificate available but we
301  want to perform a generic check that the certificate is
302  generally OK, such as not being expired */
303  status = checkCertBasic( certInfoPtr );
304  if( cryptStatusError( status ) )
305  {
306  /* Convert the status value to the correct form */
307  return( CRYPT_ARGERROR_OBJECT );
308  }
309 
310  /* Then check the validity. Because this is a nonspecific check
311  we allow any key usage */
312  keyUsageValue = CRYPT_KEYUSAGE_KEYENCIPHERMENT | \
313  KEYUSAGE_SIGN | KEYUSAGE_CA;
314  checkKeyFlag = CHECKKEY_FLAG_GENCHECK;
315  break;
316 
317  default:
318  retIntError();
319  }
320  ENSURES( keyUsageValue != CRYPT_KEYUSAGE_NONE || \
321  checkKeyFlag != CHECKKEY_FLAG_NONE );
322 
323  /* Certificate requests are special-case objects in that the key they
324  contain is usable only for signature checking of the self-signature
325  on the object (it can't be used for general-purpose usages, which
326  would make it equivalent to a trusted self-signed certificate). This
327  is problematic because the keyUsage may indicate that the key is
328  valid for other things as well, or not valid for signature checking.
329  To get around this we indicate that the key has a single trusted
330  usage, signature checking, and disallow any other usage regardless of
331  what the keyUsage says. The actual keyUsage usage is only valid once
332  the request has been converted into a certificate */
333  if( certInfoPtr->type == CRYPT_CERTTYPE_CERTREQUEST || \
334  certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT )
335  {
336  if( checkType == MESSAGE_CHECK_PKC_SIGCHECK || \
337  checkType == MESSAGE_CHECK_PKC_SIGCHECK_AVAIL )
338  return( CRYPT_OK );
341  return( CRYPT_ARGERROR_OBJECT );
342  }
343 
344  /* Only certificate objects with associated public keys are valid for
345  check messages (which are checking the capabilities of the key) */
346  REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
347  certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
348  certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
349 
350  /* Certificate collections are pure container objects for which the base
351  certificate object doesn't correspond to an actual certificate */
352  REQUIRES( !( certInfoPtr->flags & CERT_FLAG_CERTCOLLECTION ) );
353 
354  /* Check the key usage for the certificate */
355  status = krnlSendMessage( certInfoPtr->ownerHandle,
356  IMESSAGE_GETATTRIBUTE, &complianceLevel,
358  if( cryptStatusError( status ) )
359  return( status );
360  status = checkKeyUsage( certInfoPtr, checkKeyFlag, keyUsageValue,
361  complianceLevel, &certInfoPtr->errorLocus,
362  &certInfoPtr->errorType );
363  if( cryptStatusError( status ) )
364  {
365  /* Convert the status value to the correct form */
366  return( CRYPT_ARGERROR_OBJECT );
367  }
368 
369  return( CRYPT_OK );
370  }
371 
372 /* Export the certificate's data contents in ASN.1-encoded form */
373 
375 static int exportCertData( CERT_INFO *certInfoPtr,
376  IN_ENUM( CRYPT_CERTFORMAT ) \
377  const CRYPT_CERTFORMAT_TYPE certFormat,
378  OUT_BUFFER_OPT( certDataMaxLength, *certDataLength ) \
379  void *certData,
380  IN_LENGTH_Z const int certDataMaxLength,
382  {
383  int status;
384 
385  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
386  assert( ( certData == NULL && certDataMaxLength == 0 ) || \
387  isWritePtr( certData, certDataMaxLength ) );
388  assert( isWritePtr( certDataLength, sizeof( int ) ) );
389 
390  REQUIRES( certFormat > CRYPT_CERTFORMAT_NONE && \
391  certFormat < CRYPT_CERTFORMAT_LAST );
392  REQUIRES( ( certData == NULL && certDataMaxLength == 0 ) || \
393  ( certData != NULL && \
394  certDataMaxLength > 0 && \
395  certDataMaxLength < MAX_INTLENGTH ) );
396 
397  /* Clear return value */
398  *certDataLength = 0;
399 
400  /* Unsigned object types like CMS attributes aren't signed like other
401  certificate objects so they aren't pre-encoded when we sign them and
402  have the potential to change on each use if the same CMS attributes
403  are reused for multiple signatures. Because of this we write them
404  out on export rather than copying the pre-encoded form from an
405  internal buffer */
406  if( certInfoPtr->type == CRYPT_CERTTYPE_CMS_ATTRIBUTES )
407  {
408  WRITECERT_FUNCTION writeCertFunction;
409  STREAM stream;
410 
411  REQUIRES( certFormat == CRYPT_ICERTFORMAT_DATA );
412 
413  writeCertFunction = \
414  getCertWriteFunction( CRYPT_CERTTYPE_CMS_ATTRIBUTES );
415  ENSURES( writeCertFunction != NULL );
416  sMemOpenOpt( &stream, certData, certDataMaxLength );
417  status = writeCertFunction( &stream, certInfoPtr, NULL,
418  CRYPT_UNUSED );
419  if( cryptStatusOK( status ) )
420  *certDataLength = stell( &stream );
421  sMemDisconnect( &stream );
422 
423  return( status );
424  }
425 
426  /* Some objects aren't signed or are pseudo-signed or optionally signed
427  and have to be handled specially. RTCS requests and responses are
428  never signed (they're pure data containers like CMS attributes, with
429  protection being provided by CMS). OCSP requests can be optionally
430  signed but usually aren't, so if we're fed an OCSP request without
431  any associated encoded data we pseudo-sign it to produce encoded data.
432  PKI user data is never signed but needs to go through a one-off setup
433  process to initialise the user data fields, so it has the same
434  semantics as a pseudo-signed object. CRMF revocation requests are
435  never signed (thus ruling out suicide-note revocations) */
436  if( ( certInfoPtr->type == CRYPT_CERTTYPE_RTCS_REQUEST || \
437  certInfoPtr->type == CRYPT_CERTTYPE_RTCS_RESPONSE || \
438  certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST || \
439  certInfoPtr->type == CRYPT_CERTTYPE_PKIUSER || \
440  certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION ) && \
441  certInfoPtr->certificate == NULL )
442  {
443  status = signCert( certInfoPtr, CRYPT_UNUSED );
444  if( cryptStatusError( status ) )
445  return( status );
446  }
447 
448  /* If we're exporting a single certificate from a chain, lock the
449  currently selected certificate in the chain and export that */
450  if( certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN && \
451  certInfoPtr->cCertCert->chainPos >= 0 && \
452  ( certFormat == CRYPT_CERTFORMAT_CERTIFICATE || \
453  certFormat == CRYPT_CERTFORMAT_TEXT_CERTIFICATE || \
454  certFormat == CRYPT_CERTFORMAT_XML_CERTIFICATE ) )
455  {
456  CERT_INFO *certChainInfoPtr;
457 
458  ENSURES( certInfoPtr->cCertCert->chainPos >= 0 && \
459  certInfoPtr->cCertCert->chainPos < MAX_CHAINLENGTH );
460  status = krnlAcquireObject( certInfoPtr->cCertCert->chain[ certInfoPtr->cCertCert->chainPos ],
462  ( void ** ) &certChainInfoPtr,
464  if( cryptStatusError( status ) )
465  return( status );
466  status = exportCert( certData, certDataMaxLength, certDataLength,
467  certFormat, certChainInfoPtr );
468  krnlReleaseObject( certChainInfoPtr->objectHandle );
469  return( status );
470  }
471 
472  ENSURES( ( ( certInfoPtr->flags & CERT_FLAG_CERTCOLLECTION ) && \
473  certInfoPtr->certificate == NULL ) || \
474  certInfoPtr->certificate != NULL );
475  return( exportCert( certData, certDataMaxLength, certDataLength,
476  certFormat, certInfoPtr ) );
477  }
478 
479 /****************************************************************************
480 * *
481 * Internal Certificate/Key Management Functions *
482 * *
483 ****************************************************************************/
484 
485 /* Import a certificate blob or certificate chain by sending get_next_cert
486  messages to the source object to obtain all the certificates in a chain.
487  Returns the length of the certificate.
488 
489  This isn't really a direct certificate function since the control flow
490  sequence is:
491 
492  import indirect:
493  GETNEXTCERT -> source object
494  source object:
495  CREATEOBJECT_INDIRECT -> system device
496  system device: createCertificate()
497  GETNEXTCERT -> source object
498  source object:
499  CREATEOBJECT_INDIRECT -> system device
500  system device: createCertificate()
501  [...]
502 
503  however this seems to be the best place to put the code (sol lucet
504  omnibus) */
505 
507 int iCryptImportCertIndirect( OUT_HANDLE_OPT CRYPT_CERTIFICATE *iCertificate,
509  IN_ENUM( CRYPT_KEYID ) \
511  IN_BUFFER( keyIDlength ) const void *keyID,
512  IN_LENGTH_SHORT const int keyIDlength,
513  IN_FLAGS_Z( KEYMGMT ) const int options )
514  {
515  assert( isWritePtr( iCertificate, sizeof( CRYPT_CERTIFICATE ) ) );
516  assert( isReadPtr( keyID, keyIDlength ) );
517 
518  REQUIRES( isHandleRangeValid( iCertSource ) );
519  REQUIRES( keyIDtype > CRYPT_KEYID_NONE && keyIDtype < CRYPT_KEYID_LAST );
520  REQUIRES( keyIDlength > 0 && keyIDlength < MAX_INTLENGTH_SHORT );
521  REQUIRES( options >= KEYMGMT_FLAG_NONE && options < KEYMGMT_FLAG_MAX && \
522  ( options & ~KEYMGMT_MASK_CERTOPTIONS ) == 0 );
523 
524  /* Clear return value */
525  *iCertificate = CRYPT_ERROR;
526 
527  /* We're importing a sequence of certificates as a chain from a source
528  object, assemble the collection via the object */
529  return( assembleCertChain( iCertificate, iCertSource, keyIDtype,
530  keyID, keyIDlength, options ) );
531  }
532 
533 /****************************************************************************
534 * *
535 * Certificate Management API Functions *
536 * *
537 ****************************************************************************/
538 
539 /* Handle attribute data sent to or read from a certificate object. We have
540  to do this in a standalone function since it's called from several places
541  in the certificate message handler */
542 
544 static int processCertAttribute( INOUT CERT_INFO *certInfoPtr,
546  INOUT void *messageDataPtr,
548  {
549  MESSAGE_DATA *msgData = ( MESSAGE_DATA * ) messageDataPtr;
550  int *valuePtr = ( int * ) messageDataPtr;
551 
552  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
553 
554  REQUIRES( message == MESSAGE_GETATTRIBUTE || \
555  message == MESSAGE_GETATTRIBUTE_S || \
556  message == MESSAGE_SETATTRIBUTE || \
557  message == MESSAGE_SETATTRIBUTE_S || \
558  message == MESSAGE_DELETEATTRIBUTE );
559  REQUIRES( isAttribute( attribute ) || \
560  isInternalAttribute( attribute ) );
561 
562  /* Process get/set/delete attribute messages */
563  if( message == MESSAGE_GETATTRIBUTE )
564  {
565  if( attribute == CRYPT_ATTRIBUTE_ERRORTYPE )
566  {
567  *valuePtr = certInfoPtr->errorType;
568  return( CRYPT_OK );
569  }
570  if( attribute == CRYPT_ATTRIBUTE_ERRORLOCUS )
571  {
572  *valuePtr = certInfoPtr->errorLocus;
573  return( CRYPT_OK );
574  }
575  return( getCertComponent( certInfoPtr, attribute, valuePtr ) );
576  }
577  if( message == MESSAGE_GETATTRIBUTE_S )
578  return( getCertComponentString( certInfoPtr, attribute,
579  msgData->data, msgData->length,
580  &msgData->length ) );
581  if( message == MESSAGE_SETATTRIBUTE )
582  {
583  const int value = *valuePtr;
584  BOOLEAN validCursorPosition;
585 
586  if( certInfoPtr->type == CRYPT_CERTTYPE_CMS_ATTRIBUTES )
587  {
588  validCursorPosition = \
589  ( attribute >= CRYPT_CERTINFO_FIRST_CMS && \
590  attribute <= CRYPT_CERTINFO_LAST_CMS ) ? TRUE : FALSE;
591  }
592  else
593  {
594  validCursorPosition = \
595  ( attribute >= CRYPT_CERTINFO_FIRST_EXTENSION && \
596  attribute <= CRYPT_CERTINFO_LAST_EXTENSION ) ? TRUE : FALSE;
597  }
598 
599  /* If it's a completed certificate we can only add a restricted
600  class of component selection control values to the object. We
601  don't use continuation characters for the more complex isXYZ()
602  expressions because the resulting string is too long for some
603  broken compilers */
604  REQUIRES( certInfoPtr->certificate == NULL || \
605  isDNSelectionComponent( attribute ) ||
606  isGeneralNameSelectionComponent( attribute ) ||
607  /* Cursor control */
608  attribute == CRYPT_CERTINFO_CURRENT_CERTIFICATE || \
609  attribute == CRYPT_ATTRIBUTE_CURRENT_GROUP || \
610  attribute == CRYPT_ATTRIBUTE_CURRENT || \
611  attribute == CRYPT_ATTRIBUTE_CURRENT_INSTANCE ||
612  /* Cert handling control component */
613  attribute == CRYPT_CERTINFO_TRUSTED_USAGE || \
614  attribute == CRYPT_CERTINFO_TRUSTED_IMPLICIT || \
615  attribute == CRYPT_IATTRIBUTE_INITIALISED ||
616  /* Misc.components */
617  attribute == CRYPT_IATTRIBUTE_PKIUSERINFO );
618 
619  /* If it's an initialisation message, there's nothing to do (we get
620  these when importing a certificate, when the import is complete
621  the import code sends this message to move the cert into the high
622  state because it's already signed) */
623  if( attribute == CRYPT_IATTRIBUTE_INITIALISED )
624  return( CRYPT_OK );
625 
626  /* If the passed-in value is a cursor-positioning code, make sure
627  that it's valid */
628  if( value < 0 && value != CRYPT_UNUSED && \
629  ( value > CRYPT_CURSOR_FIRST || value < CRYPT_CURSOR_LAST ) &&
630  !validCursorPosition && attribute != CRYPT_CERTINFO_SELFSIGNED )
631  return( CRYPT_ARGERROR_NUM1 );
632 
633  return( addCertComponent( certInfoPtr, attribute, value ) );
634  }
635  if( message == MESSAGE_SETATTRIBUTE_S )
636  return( addCertComponentString( certInfoPtr, attribute,
637  msgData->data, msgData->length ) );
638  if( message == MESSAGE_DELETEATTRIBUTE )
639  return( deleteCertComponent( certInfoPtr, attribute ) );
640 
641  retIntError();
642  }
643 
644 /* Handle a message sent to a certificate context */
645 
647 static int certificateMessageFunction( INOUT TYPECAST( CERT_INFO * ) \
648  void *objectInfoPtr,
649  IN_MESSAGE const MESSAGE_TYPE message,
650  void *messageDataPtr,
651  IN_INT_Z const int messageValue )
652  {
653  CERT_INFO *certInfoPtr = ( CERT_INFO * ) objectInfoPtr;
654 
655  assert( isWritePtr( objectInfoPtr, sizeof( CERT_INFO ) ) );
656 
657  REQUIRES( message > MESSAGE_NONE && message < MESSAGE_LAST );
658  REQUIRES( ( message == MESSAGE_CRT_SIGCHECK && \
659  messageValue == CRYPT_UNUSED ) || \
660  ( messageValue >= 0 && messageValue < MAX_INTLENGTH ) );
661 
662  /* Process destroy object messages */
663  if( message == MESSAGE_DESTROY )
664  {
665  /* Clear the encoded certificate and miscellaneous components if
666  necessary. Note that there's no need to clear the associated
667  encryption context (if any) since this is a dependent object of
668  the certificate and is destroyed by the kernel when the cert is
669  destroyed */
670  if( certInfoPtr->certificate != NULL )
671  {
672  zeroise( certInfoPtr->certificate, certInfoPtr->certificateSize );
673  clFree( "certificateMessageFunction", certInfoPtr->certificate );
674  }
675  if( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
676  certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
677  certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN )
678  {
679  if( certInfoPtr->cCertCert->serialNumber != NULL && \
680  certInfoPtr->cCertCert->serialNumber != \
681  certInfoPtr->cCertCert->serialNumberBuffer )
682  clFree( "certificateMessageFunction",
683  certInfoPtr->cCertCert->serialNumber );
684  }
685 #ifdef USE_CERTREQ
686  if( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION )
687  {
688  if( certInfoPtr->cCertReq->serialNumber != NULL && \
689  certInfoPtr->cCertReq->serialNumber != \
690  certInfoPtr->cCertReq->serialNumberBuffer )
691  clFree( "certificateMessageFunction",
692  certInfoPtr->cCertReq->serialNumber );
693  }
694 #endif /* USE_CERTREQ */
695 #ifdef USE_CERT_OBSOLETE
696  if( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE )
697  {
698  if( certInfoPtr->cCertCert->subjectUniqueID != NULL )
699  clFree( "certificateMessageFunction",
700  certInfoPtr->cCertCert->subjectUniqueID );
701  if( certInfoPtr->cCertCert->issuerUniqueID != NULL )
702  clFree( "certificateMessageFunction",
703  certInfoPtr->cCertCert->issuerUniqueID );
704  }
705 #endif /* USE_CERT_OBSOLETE */
706  if( certInfoPtr->publicKeyData != NULL )
707  clFree( "certificateMessageFunction", certInfoPtr->publicKeyData );
708  if( certInfoPtr->subjectDNdata != NULL )
709  clFree( "certificateMessageFunction", certInfoPtr->subjectDNdata );
710  if( certInfoPtr->issuerDNdata != NULL )
711  clFree( "certificateMessageFunction", certInfoPtr->issuerDNdata );
712 #ifdef USE_CERTREV
713  if( certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
714  certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST || \
715  certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE )
716  {
717  if( certInfoPtr->cCertRev->responderUrl != NULL )
718  clFree( "certificateMessageFunction",
719  certInfoPtr->cCertRev->responderUrl );
720  }
721 #endif /* USE_CERTREV */
722 #ifdef USE_CERTVAL
723  if( certInfoPtr->type == CRYPT_CERTTYPE_RTCS_REQUEST || \
724  certInfoPtr->type == CRYPT_CERTTYPE_RTCS_RESPONSE )
725  {
726  if( certInfoPtr->cCertVal->responderUrl != NULL )
727  clFree( "certificateMessageFunction",
728  certInfoPtr->cCertVal->responderUrl );
729  }
730 #endif /* USE_CERTVAL */
731 
732  /* Clear the DN's if necessary */
733  if( certInfoPtr->issuerName != NULL )
734  deleteDN( &certInfoPtr->issuerName );
735  if( certInfoPtr->subjectName != NULL )
736  deleteDN( &certInfoPtr->subjectName );
737 
738  /* Clear the attributes and validity/revocation info if necessary */
739  if( certInfoPtr->attributes != NULL )
740  deleteAttributes( &certInfoPtr->attributes );
741 #ifdef USE_CERTVAL
742  if( certInfoPtr->type == CRYPT_CERTTYPE_RTCS_REQUEST || \
743  certInfoPtr->type == CRYPT_CERTTYPE_RTCS_RESPONSE )
744  {
745  if( certInfoPtr->cCertVal->validityInfo != NULL )
746  deleteValidityEntries( &certInfoPtr->cCertVal->validityInfo );
747  }
748 #endif /* USE_CERTVAL */
749 #ifdef USE_CERTREV
750  if( certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
751  certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST || \
752  certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE )
753  {
754  if( certInfoPtr->cCertRev->revocations != NULL )
755  deleteRevocationEntries( &certInfoPtr->cCertRev->revocations );
756  }
757 #endif /* USE_CERTREV */
758 
759  /* Clear the certificate chain if necessary */
760  if( certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN && \
761  certInfoPtr->cCertCert->chainEnd > 0 )
762  {
763  int i;
764 
765  ENSURES( certInfoPtr->cCertCert->chainEnd >= 0 && \
766  certInfoPtr->cCertCert->chainEnd < MAX_CHAINLENGTH );
767  for( i = 0; i < certInfoPtr->cCertCert->chainEnd && \
768  i < MAX_CHAINLENGTH; i++ )
769  {
770  krnlSendNotifier( certInfoPtr->cCertCert->chain[ i ],
772  }
773  ENSURES( i < MAX_CHAINLENGTH );
774  }
775 
776  return( CRYPT_OK );
777  }
778 
779  /* Process attribute get/set/delete messages */
780  if( isAttributeMessage( message ) )
781  {
782  /* If it's a certificate chain lock the currently selected
783  certificate in the chain unless the message being processed is a
784  certificate cursor movement command or something specifically
785  directed at the entire chain (for example a get type or self-
786  signed status command - we want to get the type/status of the
787  chain, not of the certificates within it) */
788  if( certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN && \
789  certInfoPtr->cCertCert->chainPos >= 0 && \
790  !( ( message == MESSAGE_SETATTRIBUTE ) && \
791  ( messageValue == CRYPT_CERTINFO_CURRENT_CERTIFICATE ) ) && \
792  !( ( message == MESSAGE_GETATTRIBUTE ) && \
793  ( messageValue == CRYPT_CERTINFO_CERTTYPE || \
794  messageValue == CRYPT_CERTINFO_SELFSIGNED ) ) )
795  {
796  CERT_INFO *certChainInfoPtr;
797  int status;
798 
799  ENSURES( certInfoPtr->cCertCert->chainPos >= 0 && \
800  certInfoPtr->cCertCert->chainPos < MAX_CHAINLENGTH );
801  status = krnlAcquireObject( certInfoPtr->cCertCert->chain[ certInfoPtr->cCertCert->chainPos ],
803  ( void ** ) &certChainInfoPtr,
805  if( cryptStatusError( status ) )
806  return( status );
807  status = processCertAttribute( certChainInfoPtr, message,
808  messageDataPtr, messageValue );
809  krnlReleaseObject( certChainInfoPtr->objectHandle );
810  return( status );
811  }
812 
813  return( processCertAttribute( certInfoPtr, message, messageDataPtr,
814  messageValue ) );
815  }
816 
817  /* Process messages that compare the object */
818  if( message == MESSAGE_COMPARE )
819  {
820  const MESSAGE_DATA *msgData = ( MESSAGE_DATA * ) messageDataPtr;
821 
822  if( messageValue == MESSAGE_COMPARE_CERTOBJ )
823  {
824  /* A certificate object compare passes in a cert handle rather
825  than data */
826  return( compareCertInfo( certInfoPtr, messageValue, NULL, 0,
827  *( ( CRYPT_CERTIFICATE * ) messageDataPtr ) ) ? \
828  CRYPT_OK : CRYPT_ERROR );
829  }
830  return( compareCertInfo( certInfoPtr, messageValue, msgData->data,
831  msgData->length, CRYPT_UNUSED ) ? \
832  CRYPT_OK : CRYPT_ERROR );
833  }
834 
835  /* Process messages that check a certificate */
836  if( message == MESSAGE_CHECK )
837  return( checkCertUsage( certInfoPtr, messageValue ) );
838 
839  /* Process internal notification messages */
840  if( message == MESSAGE_CHANGENOTIFY )
841  {
842  /* If the object is being accessed for cryptlib-internal use, save/
843  restore the internal state */
844  if( messageValue == MESSAGE_CHANGENOTIFY_STATE )
845  {
846  if( messageDataPtr == MESSAGE_VALUE_TRUE )
847  {
848  /* Save the current volatile state so that any changes made
849  while the object is in use aren't reflected back to the
850  caller after the cryptlib-internal use has completed */
851  saveSelectionState( certInfoPtr->selectionState,
852  certInfoPtr );
853  }
854  else
855  {
856  /* Restore the volatile state from before the object was
857  used */
858  restoreSelectionState( certInfoPtr->selectionState,
859  certInfoPtr );
860  }
861 
862  return( CRYPT_OK );
863  }
864 
865  retIntError();
866  }
867 
868  /* Process object-specific messages */
869  if( message == MESSAGE_CRT_SIGN )
870  {
871  int status;
872 
873  REQUIRES( certInfoPtr->certificate == NULL );
874 
875  /* Make sure that the signing object can actually be used for
876  signing */
877  status = krnlSendMessage( messageValue, IMESSAGE_CHECK, NULL,
879  if( cryptStatusError( status ) )
880  {
881  /* The only time that we can use a signing object that can't
882  sign is when we have a CRMF request, which can be created
883  with an encryption-only key if the private key POP is
884  performed via an out-of-band mechanism. If this is the case
885  we make sure that the key can decrypt, which is the other way
886  of performing POP if a signing key isn't available */
887  if( certInfoPtr->type != CRYPT_CERTTYPE_REQUEST_CERT )
888  return( CRYPT_ARGERROR_VALUE );
889  status = krnlSendMessage( messageValue, IMESSAGE_CHECK, NULL,
891  if( cryptStatusError( status ) )
892  return( CRYPT_ARGERROR_VALUE );
893  }
894 
895  /* We're changing data in a certificate, clear the error
896  information */
897  clearErrorInfo( certInfoPtr );
898 
899  return( signCert( certInfoPtr, messageValue ) );
900  }
901  if( message == MESSAGE_CRT_SIGCHECK )
902  {
903  REQUIRES( certInfoPtr->certificate != NULL || \
904  certInfoPtr->type == CRYPT_CERTTYPE_RTCS_RESPONSE || \
905  certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE );
906 
907  /* We're checking data in a certificate, clear the error
908  information */
909  clearErrorInfo( certInfoPtr );
910 
911  return( checkCertValidity( certInfoPtr, messageValue ) );
912  }
913  if( message == MESSAGE_CRT_EXPORT )
914  {
915  MESSAGE_DATA *msgData = ( MESSAGE_DATA * ) messageDataPtr;
916 
917  return( exportCertData( certInfoPtr, messageValue,
918  msgData->data, msgData->length,
919  &msgData->length ) );
920  }
921 
922  retIntError();
923  }
924 
925 /* Create a certificate object, returning a pointer to the locked
926  certificate info ready for further initialisation */
927 
929 int createCertificateInfo( OUT_OPT_PTR CERT_INFO **certInfoPtrPtr,
931  IN_ENUM( CRYPT_CERTTYPE ) \
933  {
936  OBJECT_SUBTYPE subType;
937  int storageSize, status;
938 
939  assert( isWritePtr( certInfoPtrPtr, sizeof( CERT_INFO * ) ) );
940 
941  REQUIRES( ( iCryptOwner == DEFAULTUSER_OBJECT_HANDLE ) || \
942  isHandleRangeValid( iCryptOwner ) );
943  REQUIRES( certType > CRYPT_CERTTYPE_NONE && \
944  certType < CRYPT_CERTTYPE_LAST );
945 
946  /* Clear the return values */
947  *certInfoPtrPtr = NULL;
948 
949  /* Set up subtype-specific information */
950  switch( certType )
951  {
954  subType = ( certType == CRYPT_CERTTYPE_CERTIFICATE ) ? \
956  storageSize = sizeof( CERT_CERT_INFO );
957  break;
958 
960  /* A certificate chain is a special case of a cert (and/or vice
961  versa) so it uses the same subtype-specific storage */
962  subType = SUBTYPE_CERT_CERTCHAIN;
963  storageSize = sizeof( CERT_CERT_INFO );
964  break;
965 
966 #ifdef USE_CERTREQ
968  subType = SUBTYPE_CERT_CERTREQ;
969  storageSize = 0;
970  break;
971 
974  subType = ( certType == CRYPT_CERTTYPE_REQUEST_CERT ) ? \
976  storageSize = sizeof( CERT_REQ_INFO );
977  break;
978 #endif /* USE_CERTREQ */
979 
980 #ifdef USE_CERTREV
981  case CRYPT_CERTTYPE_CRL:
982  subType = SUBTYPE_CERT_CRL;
983  storageSize = sizeof( CERT_REV_INFO );
984  break;
985 
988  subType = ( certType == CRYPT_CERTTYPE_OCSP_REQUEST ) ? \
990  storageSize = sizeof( CERT_REV_INFO );
991  break;
992 #endif /* USE_CERTREV */
993 
994 #ifdef USE_CMSATTR
996  subType = SUBTYPE_CERT_CMSATTR;
997  storageSize = 0;
998  break;
999 #endif /* USE_CMSATTR */
1000 
1001 #ifdef USE_CERTVAL
1004  subType = ( certType == CRYPT_CERTTYPE_RTCS_REQUEST ) ? \
1006  storageSize = sizeof( CERT_VAL_INFO );
1007  break;
1008 #endif /* USE_CERTVAL */
1009 
1010 #ifdef USE_PKIUSER
1012  subType = SUBTYPE_CERT_PKIUSER;
1013  storageSize = sizeof( CERT_PKIUSER_INFO );
1014  break;
1015 #endif /* USE_PKIUSER */
1016 
1017  default:
1018  /* In theory this should be a retIntError() but since some
1019  certificate types could be disabled we return a more
1020  conservative not-available error */
1021  return( CRYPT_ERROR_NOTAVAIL );
1022  }
1023 
1024  /* Create the certificate object */
1025  status = krnlCreateObject( &iCertificate, ( void ** ) &certInfoPtr,
1026  sizeof( CERT_INFO ) + storageSize,
1027  OBJECT_TYPE_CERTIFICATE, subType,
1028  CREATEOBJECT_FLAG_NONE, iCryptOwner,
1030  certificateMessageFunction );
1031  if( cryptStatusError( status ) )
1032  return( status );
1033  ANALYSER_HINT( certInfoPtr != NULL );
1034  certInfoPtr->objectHandle = iCertificate;
1035  certInfoPtr->ownerHandle = iCryptOwner;
1036  certInfoPtr->type = certType;
1037  switch( certInfoPtr->type )
1038  {
1042  certInfoPtr->cCertCert = ( CERT_CERT_INFO * ) certInfoPtr->storage;
1043  certInfoPtr->cCertCert->chainPos = CRYPT_ERROR;
1044  certInfoPtr->cCertCert->trustedUsage = CRYPT_ERROR;
1045  break;
1046 
1047 #ifdef USE_CERTREQ
1050  certInfoPtr->cCertReq = ( CERT_REQ_INFO * ) certInfoPtr->storage;
1051  break;
1052 #endif /* USE_CERTREQ */
1053 
1054 #ifdef USE_CERTREV
1055  case CRYPT_CERTTYPE_CRL:
1058  certInfoPtr->cCertRev = ( CERT_REV_INFO * ) certInfoPtr->storage;
1059  break;
1060 #endif /* USE_CERTREV */
1061 
1062 #ifdef USE_CERTVAL
1065  certInfoPtr->cCertVal = ( CERT_VAL_INFO * ) certInfoPtr->storage;
1066  break;
1067 #endif /* USE_CERTREV */
1068 
1069 #ifdef USE_PKIUSER
1071  certInfoPtr->cCertUser = ( CERT_PKIUSER_INFO * ) certInfoPtr->storage;
1072  break;
1073 #endif /* USE_PKIUSER */
1074 
1075 #ifdef USE_CERTREQ
1077  /* No special storage requirements */
1078  break;
1079 #endif /* USE_CERTREQ */
1080 
1081 #ifdef USE_CMSATTR
1083  /* No special storage requirements */
1084  break;
1085 #endif /* USE_CMSATTR */
1086 
1087  default:
1088  retIntError();
1089  }
1090 
1091  /* Set up the default version number. These values are set here mostly
1092  so that attempting to read the version attribute won't return a
1093  version of 0.
1094 
1095  In some cases this is an indication only and will be modified based
1096  on information added to the object (for example the CRL version is
1097  implicitly set based on whether extensions are added or not). If this
1098  can happen we start with the lowest version available (the default
1099  v1) which will be automatically incremented whenever information that
1100  can't be represented with that format version is added */
1101  switch( certType )
1102  {
1105  certInfoPtr->version = 3;
1106  break;
1107 
1109  certInfoPtr->version = 2;
1110  break;
1111 
1112  default:
1113  certInfoPtr->version = 1;
1114  break;
1115  }
1116 
1117  /* Set up any internal objects to contain invalid handles */
1118  certInfoPtr->iPubkeyContext = CRYPT_ERROR;
1119 
1120  /* Set the state information to its initial state */
1121  initSelectionInfo( certInfoPtr );
1122 
1123  /* Return the certificate info pointer */
1124  *certInfoPtrPtr = certInfoPtr;
1125  return( iCertificate );
1126  }
1127 
1128 /* Create a certificate */
1129 
1130 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
1131 int createCertificate( INOUT MESSAGE_CREATEOBJECT_INFO *createInfo,
1132  STDC_UNUSED const void *auxDataPtr,
1133  STDC_UNUSED const int auxValue )
1134  {
1137  int status;
1138 
1139  assert( isWritePtr( createInfo, sizeof( MESSAGE_CREATEOBJECT_INFO ) ) );
1140 
1141  REQUIRES( auxDataPtr == NULL && auxValue == 0 );
1142  REQUIRES( createInfo->arg1 > CRYPT_CERTTYPE_NONE && \
1143  createInfo->arg1 < CRYPT_CERTTYPE_LAST );
1144  REQUIRES( createInfo->arg2 == 0 && createInfo->strArg1 == NULL && \
1145  createInfo->strArgLen1 == 0 );
1146 
1147  /* Pass the call on to the lower-level open function */
1148  status = createCertificateInfo( &certInfoPtr, createInfo->cryptOwner,
1149  createInfo->arg1 );
1150  if( cryptStatusError( status ) )
1151  return( status );
1152  iCertificate = status;
1153 
1154  /* We've finished setting up the object-type-specific info, tell the
1155  kernel that the object is ready for use */
1156  status = krnlSendMessage( iCertificate, IMESSAGE_SETATTRIBUTE,
1157  MESSAGE_VALUE_OK, CRYPT_IATTRIBUTE_STATUS );
1158  if( cryptStatusOK( status ) )
1159  createInfo->cryptHandle = iCertificate;
1160  return( status );
1161  }
1162 
1163 /* Create a certificate by instantiating it from its encoded form */
1164 
1165 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
1167  STDC_UNUSED const void *auxDataPtr,
1168  STDC_UNUSED const int auxValue )
1169  {
1171  int status;
1172 
1173  assert( isWritePtr( createInfo, sizeof( MESSAGE_CREATEOBJECT_INFO ) ) );
1174 
1175  REQUIRES( auxDataPtr == NULL && auxValue == 0 );
1176  REQUIRES( createInfo->arg1 >= CRYPT_CERTTYPE_NONE && \
1177  createInfo->arg1 < CRYPT_CERTTYPE_LAST );
1178  REQUIRES( createInfo->strArg1 != NULL );
1179  REQUIRES( createInfo->strArgLen1 > 16 && \
1180  createInfo->strArgLen1 < MAX_INTLENGTH );
1181  /* May be CMS attribute (short) or a mega-CRL (long ) */
1182  REQUIRES( ( createInfo->arg2 == 0 && createInfo->strArg2 == NULL && \
1183  createInfo->strArgLen2 == 0 ) || \
1184  ( ( createInfo->arg2 == CRYPT_IKEYID_KEYID || \
1185  createInfo->arg2 == CRYPT_IKEYID_ISSUERANDSERIALNUMBER ) && \
1186  createInfo->strArg2 != NULL && \
1187  createInfo->strArgLen2 > 2 && \
1188  createInfo->strArgLen2 < MAX_INTLENGTH_SHORT ) );
1189 
1190  /* Pass the call through to the low-level import function */
1191  status = importCert( createInfo->strArg1, createInfo->strArgLen1,
1192  &iCertificate, createInfo->cryptOwner,
1193  createInfo->arg2, createInfo->strArg2,
1194  createInfo->strArgLen2, createInfo->arg1 );
1195  if( cryptStatusOK( status ) )
1196  createInfo->cryptHandle = iCertificate;
1197  return( status );
1198  }
1199 
1200 /* Generic management function for this class of object */
1201 
1202 CHECK_RETVAL \
1203 int certManagementFunction( IN_ENUM( MANAGEMENT_ACTION ) \
1204  const MANAGEMENT_ACTION_TYPE action )
1205  {
1206  REQUIRES( action == MANAGEMENT_ACTION_PRE_INIT );
1207 
1208  switch( action )
1209  {
1211  if( !checkExtensionTables() )
1212  {
1213  DEBUG_DIAG(( "Certificate class initialisation failed" ));
1214  retIntError();
1215  }
1216  return( CRYPT_OK );
1217  }
1218 
1219  retIntError();
1220  }
1221 
1222 /****************************************************************************
1223 * *
1224 * Certificate Extension Blob Functions *
1225 * *
1226 ****************************************************************************/
1227 
1228 /* Get/add/delete certificate attributes */
1229 
1230 C_NONNULL_ARG( ( 2, 3, 6 ) ) \
1232  C_IN char C_PTR oid,
1233  C_OUT int C_PTR criticalFlag,
1234  C_OUT_OPT void C_PTR extension,
1237  {
1240  BYTE binaryOID[ MAX_OID_SIZE + 8 ];
1241  void *dataPtr;
1242 #ifdef EBCDIC_CHARS
1243  char asciiOID[ CRYPT_MAX_TEXTSIZE + 1 + 8 ];
1244 #endif /* EBCDIC_CHARS */
1246 
1247  /* Perform basic parameter error checking */
1248  if( !isReadPtrConst( oid, MIN_ASCII_OIDSIZE ) )
1249  return( CRYPT_ERROR_PARAM2 );
1250  if( !isWritePtrConst( criticalFlag, sizeof( int ) ) )
1251  return( CRYPT_ERROR_PARAM3 );
1252  *criticalFlag = CRYPT_ERROR;
1253  if( extension != NULL )
1254  {
1255  if( extensionMaxLength <= 4 || \
1256  extensionMaxLength >= MAX_INTLENGTH_SHORT )
1257  return( CRYPT_ERROR_PARAM5 );
1258  if( !isWritePtr( extension, extensionMaxLength ) )
1259  return( CRYPT_ERROR_PARAM4 );
1260  memset( extension, 0, min( 16, extensionMaxLength ) );
1261  }
1262  if( !isWritePtrConst( extensionLength, sizeof( int ) ) )
1263  return( CRYPT_ERROR_PARAM6 );
1264  *extensionLength = 0;
1265  if( strlen( oid ) < MIN_ASCII_OIDSIZE || \
1266  strlen( oid ) > CRYPT_MAX_TEXTSIZE )
1267  return( CRYPT_ERROR_PARAM2 );
1268 #ifdef EBCDIC_CHARS
1269  strlcpy_s( asciiOID, CRYPT_MAX_TEXTSIZE, oid );
1270  ebcdicToAscii( asciiOID, asciiOID, strlen( asciiOID ) );
1271  if( cryptStatusError( textToOID( asciiOID, strlen( asciiOID ),
1272  binaryOID, MAX_OID_SIZE, &binaryOidLen ) )
1273  return( CRYPT_ERROR_PARAM2 );
1274 #else
1275  if( cryptStatusError( textToOID( oid, strlen( oid ), binaryOID,
1276  MAX_OID_SIZE, &binaryOidLen ) ) )
1277  return( CRYPT_ERROR_PARAM2 );
1278 #endif /* EBCDIC_CHARS */
1279 
1280  /* Perform object error checking. Normally this is handled by the
1281  kernel, however since this function accesses multiple parameters and
1282  the target isn't a cryptlib attribute we have to handle the access
1283  ourselves here. In order to avoid potential race conditions we
1284  check whether the object is internal twice, once before we lock it
1285  and again afterwards. We perform the check by reading the locked
1286  property attribute, which is always available */
1287  status = krnlSendMessage( certificate, MESSAGE_GETATTRIBUTE,
1288  &value, CRYPT_CERTINFO_CERTTYPE );
1289  if( cryptStatusError( status ) )
1290  return( CRYPT_ERROR_PARAM1 );
1291  status = krnlAcquireObject( certificate, OBJECT_TYPE_CERTIFICATE,
1292  ( void ** ) &certInfoPtr,
1294  if( cryptStatusError( status ) )
1295  return( status );
1296  status = krnlSendMessage( certificate, MESSAGE_GETATTRIBUTE, &value,
1298  if( cryptStatusError( status ) )
1299  {
1300  krnlReleaseObject( certInfoPtr->objectHandle );
1301  return( CRYPT_ERROR_PARAM1 );
1302  }
1303 
1304  /* Lock the currently selected certificate in a cert chain if
1305  necessary */
1306  if( certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN && \
1307  certInfoPtr->cCertCert->chainPos >= 0 )
1308  {
1309  CERT_INFO *certChainInfoPtr;
1310 
1311  ENSURES( certInfoPtr->cCertCert->chainPos >= 0 && \
1312  certInfoPtr->cCertCert->chainPos < MAX_CHAINLENGTH );
1313  status = krnlAcquireObject( certInfoPtr->cCertCert->chain[ certInfoPtr->cCertCert->chainPos ],
1315  ( void ** ) &certChainInfoPtr,
1317  krnlReleaseObject( certInfoPtr->objectHandle );
1318  if( cryptStatusError( status ) )
1319  return( status );
1320  certInfoPtr = certChainInfoPtr;
1321  }
1322 
1323  /* Locate the attribute identified by the OID and get its information */
1324  attributeListPtr = findAttributeByOID( certInfoPtr->attributes,
1325  binaryOID, binaryOidLen );
1326  if( attributeListPtr == NULL )
1327  {
1328  krnlReleaseObject( certInfoPtr->objectHandle );
1329  return( CRYPT_ERROR_NOTFOUND );
1330  }
1331  status = getAttributeDataPtr( attributeListPtr, &dataPtr, &dataLength );
1332  if( cryptStatusError( status ) )
1333  {
1334  krnlReleaseObject( certInfoPtr->objectHandle );
1335  return( status );
1336  }
1337  *criticalFlag = checkAttributeProperty( attributeListPtr,
1339  TRUE : FALSE;
1340  status = attributeCopyParams( extension, extensionMaxLength,
1341  extensionLength, dataPtr, dataLength );
1342  krnlReleaseObject( certInfoPtr->objectHandle );
1343  return( status );
1344  }
1345 
1347  C_IN char C_PTR oid, C_IN int criticalFlag,
1348  C_IN void C_PTR extension,
1349  C_IN int extensionLength )
1350  {
1352  BYTE binaryOID[ MAX_OID_SIZE + 8 ];
1353 #ifdef EBCDIC_CHARS
1354  char asciiOID[ CRYPT_MAX_TEXTSIZE + 1 + 8 ];
1355 #endif /* EBCDIC_CHARS */
1356  int binaryOidLen, value, status;
1357 
1358  /* Perform basic parameter error checking */
1359  if( !isReadPtrConst( oid, MIN_ASCII_OIDSIZE ) )
1360  return( CRYPT_ERROR_PARAM2 );
1361  if( extensionLength <= 4 || extensionLength > MAX_ATTRIBUTE_SIZE )
1362  return( CRYPT_ERROR_PARAM5 );
1363  if( !isReadPtr( extension, extensionLength ) || \
1364  cryptStatusError( checkObjectEncoding( extension, \
1365  extensionLength ) ) )
1366  return( CRYPT_ERROR_PARAM4 );
1367  if( strlen( oid ) < MIN_ASCII_OIDSIZE || \
1368  strlen( oid ) > CRYPT_MAX_TEXTSIZE )
1369  return( CRYPT_ERROR_PARAM2 );
1370 #ifdef EBCDIC_CHARS
1371  strlcpy_s( asciiOID, CRYPT_MAX_TEXTSIZE, oid );
1372  ebcdicToAscii( asciiOID, asciiOID, strlen( asciiOID ) );
1373  if( cryptStatusError( textToOID( asciiOID, strlen( asciiOID ),
1374  binaryOID, MAX_OID_SIZE, &binaryOidLen ) ) )
1375  return( CRYPT_ERROR_PARAM2 );
1376 #else
1377  if( cryptStatusError( textToOID( oid, strlen( oid ), binaryOID,
1378  MAX_OID_SIZE, &binaryOidLen ) ) )
1379  return( CRYPT_ERROR_PARAM2 );
1380 #endif /* EBCDIC_CHARS */
1381 
1382  /* Perform object error checking. Normally this is handled by the
1383  kernel, however since this function accesses multiple parameters and
1384  the target isn't a cryptlib attribute we have to handle the access
1385  ourselves here. In order to avoid potential race conditions we
1386  check whether the object is internal twice, once before we lock it
1387  and again afterwards. We perform the check by reading the locked
1388  property attribute, which is always available */
1389  status = krnlSendMessage( certificate, MESSAGE_GETATTRIBUTE,
1390  &value, CRYPT_CERTINFO_CERTTYPE );
1391  if( cryptStatusError( status ) )
1392  return( CRYPT_ERROR_PARAM1 );
1393  status = krnlAcquireObject( certificate, OBJECT_TYPE_CERTIFICATE,
1394  ( void ** ) &certInfoPtr,
1396  if( cryptStatusError( status ) )
1397  return( status );
1398  status = krnlSendMessage( certificate, MESSAGE_GETATTRIBUTE, &value,
1400  if( cryptStatusError( status ) )
1401  {
1402  krnlReleaseObject( certInfoPtr->objectHandle );
1403  return( CRYPT_ERROR_PARAM1 );
1404  }
1405  if( certInfoPtr->certificate != NULL || \
1406  ( certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN && \
1407  certInfoPtr->cCertCert->chainPos >= 0 ) )
1408  {
1409  krnlReleaseObject( certInfoPtr->objectHandle );
1410  return( CRYPT_ERROR_PERMISSION );
1411  }
1412  if( certInfoPtr->type == CRYPT_CERTTYPE_CMS_ATTRIBUTES && \
1413  criticalFlag != CRYPT_UNUSED )
1414  {
1415  krnlReleaseObject( certInfoPtr->objectHandle );
1416  return( CRYPT_ERROR_PARAM3 );
1417  }
1418 
1419  /* Add the attribute to the certificate */
1420  status = addAttribute( \
1421  ( certInfoPtr->type == CRYPT_CERTTYPE_CMS_ATTRIBUTES ) ? \
1423  &certInfoPtr->attributes, binaryOID, binaryOidLen,
1424  ( certInfoPtr->type == CRYPT_CERTTYPE_CMS_ATTRIBUTES ) ? \
1425  FALSE : criticalFlag,
1426  extension, extensionLength, 0 );
1427  if( status == CRYPT_ERROR_INITED )
1428  {
1429  /* If the attribute is already present, set error information for it.
1430  We can't set an error locus since it's an unknown blob */
1431  setErrorInfo( certInfoPtr, CRYPT_ATTRIBUTE_NONE,
1433  }
1434  krnlReleaseObject( certInfoPtr->objectHandle );
1435  return( status );
1436  }
1437 
1439  C_IN char C_PTR oid )
1440  {
1443  BYTE binaryOID[ MAX_OID_SIZE + 8 ];
1444 #ifdef EBCDIC_CHARS
1445  char asciiOID[ CRYPT_MAX_TEXTSIZE + 1 + 8 ];
1446 #endif /* EBCDIC_CHARS */
1447  int binaryOidLen, value, status;
1448 
1449  /* Perform basic parameter error checking */
1450  if( !isReadPtrConst( oid, MIN_ASCII_OIDSIZE ) )
1451  return( CRYPT_ERROR_PARAM2 );
1452  if( strlen( oid ) < MIN_ASCII_OIDSIZE || \
1453  strlen( oid ) > CRYPT_MAX_TEXTSIZE )
1454  return( CRYPT_ERROR_PARAM2 );
1455 #ifdef EBCDIC_CHARS
1456  strlcpy_s( asciiOID, CRYPT_MAX_TEXTSIZE, oid );
1457  ebcdicToAscii( asciiOID, asciiOID, strlen( asciiOID ) );
1458  if( cryptStatusError( textToOID( asciiOID, strlen( asciiOID ),
1459  binaryOID, MAX_OID_SIZE, &binaryOidLen ) ) )
1460  return( CRYPT_ERROR_PARAM2 );
1461 #else
1462  if( cryptStatusError( textToOID( oid, strlen( oid ), binaryOID,
1463  MAX_OID_SIZE, &binaryOidLen ) ) )
1464  return( CRYPT_ERROR_PARAM2 );
1465 #endif /* EBCDIC_CHARS */
1466 
1467  /* Perform object error checking. Normally this is handled by the
1468  kernel, however since this function accesses multiple parameters and
1469  the target isn't a cryptlib attribute we have to handle the access
1470  ourselves here. In order to avoid potential race conditions we
1471  check whether the object is internal twice, once before we lock it
1472  and again afterwards. We perform the check by reading the locked
1473  property attribute, which is always available */
1474  status = krnlSendMessage( certificate, MESSAGE_GETATTRIBUTE,
1475  &value, CRYPT_CERTINFO_CERTTYPE );
1476  if( cryptStatusError( status ) )
1477  return( CRYPT_ERROR_PARAM1 );
1478  status = krnlAcquireObject( certificate, OBJECT_TYPE_CERTIFICATE,
1479  ( void ** ) &certInfoPtr,
1481  if( cryptStatusError( status ) )
1482  return( status );
1483  status = krnlSendMessage( certificate, MESSAGE_GETATTRIBUTE, &value,
1485  if( cryptStatusError( status ) )
1486  {
1487  krnlReleaseObject( certInfoPtr->objectHandle );
1488  return( CRYPT_ERROR_PARAM1 );
1489  }
1490  if( certInfoPtr->certificate != NULL || \
1491  ( certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN && \
1492  certInfoPtr->cCertCert->chainPos >= 0 ) )
1493  {
1494  krnlReleaseObject( certInfoPtr->objectHandle );
1495  return( CRYPT_ERROR_PERMISSION );
1496  }
1497 
1498  /* Find the attribute identified by the OID and delete it */
1499  attributeListPtr = findAttributeByOID( certInfoPtr->attributes,
1500  binaryOID, binaryOidLen );
1501  if( attributeListPtr == NULL )
1502  status = CRYPT_ERROR_NOTFOUND;
1503  else
1504  deleteAttribute( &certInfoPtr->attributes, NULL, attributeListPtr,
1505  NULL );
1506  krnlReleaseObject( certInfoPtr->objectHandle );
1507  return( status );
1508  }
1509 #endif /* USE_CERTIFICATES */