cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
comp_cert.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 * Utility Routines *
25 * *
26 ****************************************************************************/
27 
28 #if defined( USE_CERTREQ ) || defined( USE_CERTREV )
29 
30 /* Copy the encoded issuer DN */
31 
32 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
33 static int copyIssuerDnData( INOUT CERT_INFO *destCertInfoPtr,
34  const CERT_INFO *srcCertInfoPtr )
35  {
36  void *dnDataPtr;
37 
38  assert( isWritePtr( destCertInfoPtr, sizeof( CERT_INFO ) ) );
39  assert( isReadPtr( srcCertInfoPtr, sizeof( CERT_INFO ) ) );
40 
41  REQUIRES( srcCertInfoPtr->issuerDNptr != NULL );
42 
43  if( ( dnDataPtr = clAlloc( "copyIssuerDnData",
44  srcCertInfoPtr->issuerDNsize ) ) == NULL )
45  return( CRYPT_ERROR_MEMORY );
46  memcpy( dnDataPtr, srcCertInfoPtr->issuerDNptr,
47  srcCertInfoPtr->issuerDNsize );
48  destCertInfoPtr->issuerDNptr = destCertInfoPtr->issuerDNdata = dnDataPtr;
49  destCertInfoPtr->issuerDNsize = srcCertInfoPtr->issuerDNsize;
50 
51  return( CRYPT_OK );
52  }
53 #endif /* USE_CERTREQ || USE_CERTREV */
54 
55 #if defined( USE_CERTREV ) || defined( USE_CERTVAL )
56 
57 /* Copy an RTCS or OCSP responder URL from a certificate into a request */
58 
59 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
60 static int copyResponderURL( INOUT CERT_INFO *requestInfoPtr,
61  INOUT CERT_INFO *userCertInfoPtr )
62  {
63  const CRYPT_ATTRIBUTE_TYPE aiaAttribute = \
64  ( requestInfoPtr->type == CRYPT_CERTTYPE_RTCS_REQUEST ) ? \
67  SELECTION_STATE savedState;
68  void *responderUrl;
69  int urlSize = DUMMY_INIT, status;
70 
71  REQUIRES( requestInfoPtr->type == CRYPT_CERTTYPE_RTCS_REQUEST || \
72  requestInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST );
73  REQUIRES( userCertInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
74  userCertInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
75 
76  /* There's no responder URL set, check whether the user certificate
77  contains a responder URL in the RTCS/OCSP authorityInfoAccess
78  GeneralName */
79  saveSelectionState( savedState, userCertInfoPtr );
80  status = selectGeneralName( userCertInfoPtr, aiaAttribute,
81  MAY_BE_ABSENT );
82  if( cryptStatusOK( status ) )
83  status = selectGeneralName( userCertInfoPtr,
86  if( cryptStatusOK( status ) )
87  status = getCertComponentString( userCertInfoPtr,
89  NULL, 0, &urlSize );
90  if( cryptStatusError( status ) )
91  {
92  /* If there's no responder URL present then it's not a (fatal)
93  error */
94  restoreSelectionState( savedState, userCertInfoPtr );
95  return( CRYPT_OK );
96  }
97 
98  /* There's a responder URL present, copy it to the request */
99  if( ( responderUrl = clAlloc( "copyResponderURL", urlSize ) ) == NULL )
100  {
101  restoreSelectionState( savedState, userCertInfoPtr );
102  return( CRYPT_ERROR_MEMORY );
103  }
104  status = getCertComponentString( userCertInfoPtr,
106  responderUrl, urlSize, &urlSize );
107  if( cryptStatusOK( status ) )
108  {
109  if( requestInfoPtr->type == CRYPT_CERTTYPE_RTCS_REQUEST )
110  {
111  requestInfoPtr->cCertVal->responderUrl = responderUrl;
112  requestInfoPtr->cCertVal->responderUrlSize = urlSize;
113  }
114  else
115  {
116  requestInfoPtr->cCertRev->responderUrl = responderUrl;
117  requestInfoPtr->cCertRev->responderUrlSize = urlSize;
118  }
119  }
120  else
121  {
122  clFree( "copyResponderURL", responderUrl );
123  }
124  restoreSelectionState( savedState, userCertInfoPtr );
125 
126  return( status );
127  }
128 #endif /* USE_CERTREV || USE_CERTVAL */
129 
130 #if defined( USE_CERTREQ ) || defined( USE_CERTREV )
131 
132 /* Copy revocation information into a CRL or revocation request */
133 
134 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
135 static int copyRevocationInfo( INOUT CERT_INFO *certInfoPtr,
136  const CERT_INFO *revInfoPtr )
137  {
138  const void *serialNumberPtr;
139  int serialNumberLength, status = CRYPT_OK;
140 
141  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
142  assert( isReadPtr( revInfoPtr, sizeof( CERT_INFO ) ) );
143  assert( isReadPtr( revInfoPtr->issuerDNptr,
144  revInfoPtr->issuerDNsize ) );
145 
146  REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
147  certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION );
148  REQUIRES( revInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
149  revInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
150  revInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN || \
151  revInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION );
152  REQUIRES( revInfoPtr->issuerDNptr != NULL );
153 
154  /* If there's an issuer name recorded make sure that it matches the one
155  in the certificate that's being added */
156  if( certInfoPtr->issuerDNptr != NULL )
157  {
158  if( certInfoPtr->issuerDNsize != revInfoPtr->issuerDNsize || \
159  memcmp( certInfoPtr->issuerDNptr, revInfoPtr->issuerDNptr,
160  certInfoPtr->issuerDNsize ) )
161  {
164  status = CRYPT_ERROR_INVALID;
165  }
166  }
167  else
168  {
169  /* There's no issuer name present yet, set the CRL issuer name to
170  the certificate's issuer to make sure that we can't add
171  certificates or sign the CRL with a different issuer. We do this
172  here rather than after setting the revocation list entry because
173  of the difficulty of undoing the revocation entry addition */
174  status = copyIssuerDnData( certInfoPtr, revInfoPtr );
175  }
176  if( cryptStatusError( status ) )
177  return( status );
178 
179  /* Add the certificate information to the revocation list and make it
180  the currently selected entry. The ID type isn't quite an
181  issuerAndSerialNumber but the checking code eventually converts it
182  into this form using the supplied issuer certificate DN */
183  if( revInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION )
184  {
185  serialNumberPtr = revInfoPtr->cCertReq->serialNumber;
186  serialNumberLength = revInfoPtr->cCertReq->serialNumberLength;
187  }
188  else
189  {
190  serialNumberPtr = revInfoPtr->cCertCert->serialNumber;
191  serialNumberLength = revInfoPtr->cCertCert->serialNumberLength;
192  }
193  status = addRevocationEntry( &certInfoPtr->cCertRev->revocations,
194  &certInfoPtr->cCertRev->currentRevocation,
195  CRYPT_IKEYID_ISSUERANDSERIALNUMBER,
196  serialNumberPtr, serialNumberLength, FALSE );
197  if( status == CRYPT_ERROR_DUPLICATE )
198  {
199  /* If this certificate is already present in the list set the
200  extended error code for it */
203  }
204  return( status );
205  }
206 #endif /* USE_CERTREQ || USE_CERTREV */
207 
208 /****************************************************************************
209 * *
210 * Copy Certificate Data *
211 * *
212 ****************************************************************************/
213 
214 /* Copy public key data into a certificate object */
215 
217 int copyPublicKeyInfo( INOUT CERT_INFO *certInfoPtr,
219  IN_OPT const CERT_INFO *srcCertInfoPtr )
220  {
221  void *publicKeyInfoPtr;
222  int length = DUMMY_INIT, status;
223 
224  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
225  assert( ( isHandleRangeValid( cryptHandle ) && \
226  srcCertInfoPtr == NULL ) || \
227  ( cryptHandle == CRYPT_UNUSED && \
228  isReadPtr( srcCertInfoPtr, sizeof( CERT_INFO ) ) ) );
229 
230  REQUIRES( ( isHandleRangeValid( cryptHandle ) && \
231  srcCertInfoPtr == NULL ) || \
232  ( cryptHandle == CRYPT_UNUSED && \
233  srcCertInfoPtr != NULL ) );
234  REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
235  certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
236  certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN || \
237  certInfoPtr->type == CRYPT_CERTTYPE_CERTREQUEST || \
238  certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT );
239  REQUIRES( srcCertInfoPtr == NULL || \
240  srcCertInfoPtr->type == CRYPT_CERTTYPE_CERTREQUEST || \
241  srcCertInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT );
242 
243  /* Make sure that we haven't already got a public key present */
244  if( certInfoPtr->iPubkeyContext != CRYPT_ERROR || \
245  certInfoPtr->publicKeyInfo != NULL )
246  {
249  return( CRYPT_ERROR_INITED );
250  }
251 
252  /* If we've been given a data-only certificate copy over the public key
253  data */
254  if( srcCertInfoPtr != NULL )
255  {
256  REQUIRES( memcmp( srcCertInfoPtr->publicKeyID,
257  "\x00\x00\x00\x00\x00\x00\x00\x00", 8 ) );
258 
259  length = srcCertInfoPtr->publicKeyInfoSize;
260  if( ( publicKeyInfoPtr = clAlloc( "copyPublicKeyInfo",
261  length ) ) == NULL )
262  return( CRYPT_ERROR_MEMORY );
263  memcpy( publicKeyInfoPtr, srcCertInfoPtr->publicKeyInfo, length );
264  certInfoPtr->publicKeyAlgo = srcCertInfoPtr->publicKeyAlgo;
265  certInfoPtr->publicKeyFeatures = srcCertInfoPtr->publicKeyFeatures;
266  memcpy( certInfoPtr->publicKeyID, srcCertInfoPtr->publicKeyID,
267  KEYID_SIZE );
268  }
269  else
270  {
273 
274  /* Get the context handle. All other checking has already been
275  performed by the kernel */
276  status = krnlSendMessage( cryptHandle, IMESSAGE_GETDEPENDENT,
277  &iCryptContext, OBJECT_TYPE_CONTEXT );
278  if( cryptStatusError( status ) )
279  {
282  return( status );
283  }
284 
285  /* Get the key information */
286  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
287  &certInfoPtr->publicKeyAlgo,
289  if( cryptStatusOK( status ) )
290  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
291  &certInfoPtr->publicKeyFeatures,
292  CRYPT_IATTRIBUTE_KEYFEATURES );
293  if( cryptStatusOK( status ) )
294  {
295  setMessageData( &msgData, certInfoPtr->publicKeyID, KEYID_SIZE );
296  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
297  &msgData, CRYPT_IATTRIBUTE_KEYID );
298  }
299  if( cryptStatusError( status ) )
300  return( status );
301 
302  /* Copy over the public-key data. We copy the data rather than
303  keeping a reference to the context for two reasons. Firstly,
304  when the certificate is transitioned into the high state it will
305  constrain the attached context so a context shared between two
306  certificates could be constrained in unexpected ways. Secondly,
307  the context could be a private-key context and attaching that to
308  a certificate would be rather inappropriate. Furthermore, the
309  constraint issue is even more problematic in that a context
310  constrained by an encryption-only request could then no longer be
311  used to sign the request or a PKI protocol message containing the
312  request */
313  setMessageData( &msgData, NULL, 0 );
314  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
315  &msgData, CRYPT_IATTRIBUTE_KEY_SPKI );
316  if( cryptStatusError( status ) )
317  return( status );
318  length = msgData.length;
319  if( ( publicKeyInfoPtr = clAlloc( "copyPublicKeyInfo",
320  length ) ) == NULL )
321  return( CRYPT_ERROR_MEMORY );
322  setMessageData( &msgData, publicKeyInfoPtr, length );
323  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
324  &msgData, CRYPT_IATTRIBUTE_KEY_SPKI );
325  if( cryptStatusError( status ) )
326  return( status );
327  }
328  certInfoPtr->publicKeyData = certInfoPtr->publicKeyInfo = \
329  publicKeyInfoPtr;
330  certInfoPtr->publicKeyInfoSize = length;
331  certInfoPtr->flags |= CERT_FLAG_DATAONLY;
332 
333  return( CRYPT_OK );
334  }
335 
336 /* Sanitise certificate attributes based on a user-supplied template. This
337  is used to prevent a user from supplying potentially dangerous attributes
338  in a certificate request, for example to request a CA certificate by
339  setting the basicConstraints/keyUsage = CA extensions in the request in a
340  manner that would result in the creation of a CA certificate when the
341  request is processed.
342 
343  There are two ways to do this, either with a whitelist or with a
344  blacklist. Obviously the preferred option is the whitelist one, but the
345  problem with this is that without any knowledge of the environment into
346  which it's being deployed we have no idea what should be permitted. For
347  example an RA, which acts as a trusted agent for the CA, probably wants
348  fuller control over the form of the certificate with a wider selection of
349  attributes permitted while a CA dealing directly with the public probably
350  wants few or no attributes permitted. This is a variation of the
351  firewall configuration problem, lock it down by default and users will
352  complain, leave it open by default and users are happy but it's not secure.
353 
354  What we use here is in effect a blend of whitelist and blacklist. On
355  the whitelist side the only attributes that are permitted in certificate
356  requests are:
357 
358  CRYPT_CERTINFO_CHALLENGEPASSWORD: Needed for SCEP.
359  CRYPT_CERTINFO_KEYFEATURES: Only used by cryptlib for its own purposes.
360  CRYPT_CERTINFO_KEYUSAGE
361  CRYPT_CERTINFO_SUBJECTALTNAME
362  CRYPT_CERTINFO_EXTKEYUSAGE
363 
364  For revocation requests we allow rather more values since they're
365  required by the client to inform the CA why the certificate is being
366  revoked. Except for the invalidity date they're not so much of a
367  security threat, and even for the date the consistency vs. accuracy issue
368  for CRLs debate means the CA will put who knows what date in the CRL
369  anyway):
370 
371  CRYPT_CERTINFO_CRLEXTREASON
372  CRYPT_CERTINFO_CRLREASON
373  CRYPT_CERTINFO_HOLDINSTRUCTIONCODE
374  CRYPT_CERTINFO_INVALIDITYDATE
375 
376  Everything else, including the all-important basicConstraints, has to be
377  set explicitly by the CA and can't be specified in a request.
378 
379  On the blacklist side, multi-AVA RDNs are disallowed in order to prevent
380  an attacker from playing games with DN forms. This should be safe
381  because the only things that create such weird DNs tend to be European
382  in-house CAs following (or justifying their bugs through) peculiar
383  requirements in digital signature legislation, who will be creating their
384  own certificates from scratch themselves rather than using cryptlib for
385  it */
386 
388 static int checkCertWellFormed( INOUT CERT_INFO *certInfoPtr )
389  {
390  int status;
391 
392  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
393 
394  /* Check that the subject DN is well-formed. There can potentially be
395  any number of other DNs in a certificate (either as the issuer DN or
396  hidden in GeneralName fields), it's not really certain what we should
397  do with these (or even how we can effectively track them all down).
398  Since the reason why we're doing this in the first place is to avoid
399  shenanigans due to the more or less arbitrary handling of complex DNs
400  by implementations, and the only one that anyone really pays any
401  attention to is the subject name, we only check the subject name */
402  status = checkDN( certInfoPtr->subjectName,
405  &certInfoPtr->errorLocus,
406  &certInfoPtr->errorType );
407  if( cryptStatusError( status ) )
408  return( status );
409 
410 #if 0 /* Not really sure what else we should be checking for, or
411  disallowing, here */
412  SELECTION_STATE selectionState;
413 
414  /* Check that the subject altName is well-formed. The reason for
415  checking just this particular field are as for the subject DN check
416  above */
417  saveSelectionState( selectionState, certInfoPtr );
418  status = addCertComponent( certInfoPtr, CRYPT_ATTRIBUTE_CURRENT,
420  if( cryptStatusOK( status ) )
421  {
422  }
423  restoreSelectionState( selectionState, certInfoPtr );
424 #endif /* 0 */
425 
426  return( CRYPT_OK );
427  }
428 
430 static int sanitiseCertAttributes( INOUT CERT_INFO *certInfoPtr,
431  IN_OPT const ATTRIBUTE_PTR *templateListPtr )
432  {
433  const ATTRIBUTE_PTR *templateAttributeCursor;
434  ATTRIBUTE_ENUM_INFO attrEnumInfo;
435  int iterationCount;
436 
437  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
438  assert( templateListPtr == NULL || \
439  ( isReadPtr( templateListPtr, sizeof( ATTRIBUTE_PTR_STORAGE ) ) ) );
440 
441  REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
442  certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
443  certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
444 
445  /* If there are no attributes present or there's no disallowed-attribute
446  template, we just need to apply the well-formedness check on the way
447  out */
448  if( certInfoPtr->attributes == NULL || templateListPtr == NULL )
449  return( checkCertWellFormed( certInfoPtr ) );
450 
451  /* Walk down the template attribute list applying each one in turn to
452  the certificate attributes */
453  for( templateAttributeCursor = \
454  getFirstAttribute( &attrEnumInfo, templateListPtr, \
456  iterationCount = 0;
457  templateAttributeCursor != NULL && \
458  iterationCount < FAILSAFE_ITERATIONS_MAX;
459  templateAttributeCursor = getNextAttribute( &attrEnumInfo ), \
460  iterationCount++ )
461  {
463  ATTRIBUTE_PTR *certAttributePtr;
464  int status;
465 
466  /* Check to see whether there's a constrained attribute present in
467  the certificate attributes and if it is, whether it conflicts
468  with the constraining attribute */
469  status = getAttributeIdInfo( templateAttributeCursor, NULL,
470  &fieldID, &subFieldID );
471  if( cryptStatusError( status ) )
472  return( status );
473  certAttributePtr = findAttributeField( certInfoPtr->attributes,
474  fieldID, subFieldID );
475  if( certAttributePtr == NULL )
476  {
477  /* There's nothing to constrain present in the certificate,
478  continue */
479  continue;
480  }
481 
482  /* If the certificate attribute was provided through the application
483  of PKI user data (indicated by it having the locked flag set),
484  allow it even if it conflicts with the constraining attribute.
485  This is permitted because the PKI user data was explicitly set by
486  the issuing CA rather than being user-supplied in the certificate
487  request so it has to be OK, or at least CA-approved */
488  if( checkAttributeProperty( certAttributePtr,
490  continue;
491 
492 #if 0 /* 10/5/09 The original behaviour of this function was as its name
493  suggests, disallowed attribute values were selectively
494  disabled and, if any permitted values were still present,
495  the remainder were allowed (this assumed that the value
496  was a bitflag, which occurs for the only attribute that's
497  currently handled this way, the keyUsage). However this
498  probably isn't the right behaviour, if there's any
499  disallowed information present then the certificate-
500  creation process as a whole should be rejected rather
501  than returning a certificate that's different from what
502  was requested */
503  int constrainedAttributeValue, constrainingAttributeValue;
504 
505  /* Get the attribute values and, if there's no conflict, continue */
506  status = getAttributeDataValue( certAttributePtr,
507  &constrainedAttributeValue );
508  if( cryptStatusError( status ) )
509  return( status );
510  status = getAttributeDataValue( templateAttributeCursor,
511  &constrainingAttributeValue );
512  if( cryptStatusError( status ) )
513  return( status );
514  if( !( constrainedAttributeValue & constrainingAttributeValue ) )
515  continue;
516 
517  /* The attribute contains a value that's disallowed by the
518  constraining attribute, correct it if possible */
519  value = constrainedAttributeValue & ~constrainingAttributeValue;
520  if( value <= 0 )
521  {
522  /* The attribute contains only invalid bits and can't be
523  permitted */
524  status = getAttributeIdInfo( certAttributePtr, NULL, &fieldID,
525  NULL );
526  if( cryptStatusOK( status ) )
527  {
528  certInfoPtr->errorLocus = fieldID;
529  certInfoPtr->errorType = CRYPT_ERRTYPE_ATTR_VALUE;
530  }
531  return( CRYPT_ERROR_INVALID );
532  }
533  setAttributeProperty( certAttributePtr, ATTRIBUTE_PROPERTY_VALUE,
534  value ); /* Set adjusted value */
535 #else
536  /* There are conflicting attributes present, disallow the
537  certificate issue */
538  status = getAttributeIdInfo( certAttributePtr, NULL, &fieldID,
539  NULL );
540  if( cryptStatusError( status ) )
541  return( status );
542  if( fieldID == CRYPT_CERTINFO_KEYUSAGE )
543  {
544  int constrainedAttributeValue, constrainingAttributeValue;
545 
546  /* There is one special case in which conflicting attributes
547  are allowed and that's for keyUsage (or more generally
548  bitfields), since we can selectively disallow dangerous bit
549  values while allowing safe ones */
550  status = getAttributeDataValue( certAttributePtr,
551  &constrainedAttributeValue );
552  if( cryptStatusError( status ) )
553  return( status );
554  status = getAttributeDataValue( templateAttributeCursor,
555  &constrainingAttributeValue );
556  if( cryptStatusError( status ) )
557  return( status );
558  if( !( constrainedAttributeValue & constrainingAttributeValue ) )
559  continue;
560  }
561  certInfoPtr->errorLocus = fieldID;
562  certInfoPtr->errorType = CRYPT_ERRTYPE_ATTR_VALUE;
563  return( CRYPT_ERROR_INVALID );
564 #endif /* 0 */
565  }
566  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MAX );
567 
568  return( checkCertWellFormed( certInfoPtr ) );
569  }
570 
571 /****************************************************************************
572 * *
573 * Copy Certificate Request Data *
574 * *
575 ****************************************************************************/
576 
577 #ifdef USE_CERTREQ
578 
579 /* Copy certificate request information into a certificate object. This
580  copies the public key context, the DN, any valid attributes, and any other
581  relevant bits and pieces if it's a CRMF request */
582 
583 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
584 static int copyCertReqToCert( INOUT CERT_INFO *certInfoPtr,
585  INOUT CERT_INFO *certRequestInfoPtr )
586  {
587  int status;
588 
589  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
590  assert( isWritePtr( certRequestInfoPtr, sizeof( CERT_INFO ) ) );
591 
592  REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
593  certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
594  certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
595  REQUIRES( certRequestInfoPtr->type == CRYPT_CERTTYPE_CERTREQUEST || \
596  certRequestInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT );
597 
598  /* Copy the public key context, the DN, and the attributes. Type
599  checking has already been performed by the kernel. We copy the
600  attributes across after the DN because that copy is the hardest to
601  undo: If there are already attributes present then the copied
602  attributes would be mixed in among them so it's not really possible
603  to undo the copy later without performing a complex selective
604  delete */
605  status = copyDN( &certInfoPtr->subjectName,
606  certRequestInfoPtr->subjectName );
607  if( cryptStatusError( status ) )
608  return( status );
609  if( certRequestInfoPtr->flags & CERT_FLAG_DATAONLY )
610  {
611  status = copyPublicKeyInfo( certInfoPtr, CRYPT_UNUSED,
612  certRequestInfoPtr );
613  }
614  else
615  {
616  status = copyPublicKeyInfo( certInfoPtr,
617  certRequestInfoPtr->iPubkeyContext,
618  NULL );
619  }
620  if( cryptStatusOK( status ) && \
621  certRequestInfoPtr->attributes != NULL )
622  {
623  status = copyAttributes( &certInfoPtr->attributes,
624  certRequestInfoPtr->attributes,
625  &certInfoPtr->errorLocus,
626  &certInfoPtr->errorType );
627  if( cryptStatusError( status ) )
628  deleteDN( &certInfoPtr->subjectName );
629  }
630  if( cryptStatusError( status ) )
631  return( status );
632 
633  /* If it's a CRMF request there could also be a validity period
634  specified */
635  if( certRequestInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT )
636  {
637  const time_t currentTime = getApproxTime();
638 
639  /* We don't allow start times backdated by more than a year or end
640  times before the start time. Since these are trivial things we
641  don't abort if there's a problem but just quietly fix the value */
642  if( certRequestInfoPtr->startTime > MIN_TIME_VALUE && \
643  certRequestInfoPtr->startTime > currentTime - ( 86400L * 365 ) )
644  certInfoPtr->startTime = certRequestInfoPtr->startTime;
645  if( certRequestInfoPtr->endTime > MIN_TIME_VALUE && \
646  certRequestInfoPtr->endTime > certInfoPtr->startTime )
647  certInfoPtr->endTime = certRequestInfoPtr->endTime;
648  }
649 
650  return( CRYPT_OK );
651  }
652 
653 /* Copy what we need to identify the certificate to be revoked and any
654  revocation information into a certificate object */
655 
656 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
657 static int copyRevReqToCert( INOUT CERT_INFO *certInfoPtr,
658  INOUT CERT_INFO *revRequestInfoPtr )
659  {
660  int status;
661 
662  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
663  assert( isWritePtr( revRequestInfoPtr, sizeof( CERT_INFO ) ) );
664 
665  REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CRL );
666  REQUIRES( revRequestInfoPtr->type == CRYPT_CERTTYPE_CERTREQUEST || \
667  revRequestInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION );
668 
669  status = copyRevocationInfo( certInfoPtr, revRequestInfoPtr );
670  if( cryptStatusError( status ) || \
671  revRequestInfoPtr->attributes == NULL )
672  return( status );
673  return( copyRevocationAttributes( &certInfoPtr->attributes,
674  revRequestInfoPtr->attributes ) );
675  }
676 
677 /* Copy the public key, DN, and any attributes that need to be copied across.
678  We copy the full DN rather than just the encoded form in case the user
679  wants to query the request details after creating it */
680 
681 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
682 static int copyCertToRequest( INOUT CERT_INFO *crmfRequestInfoPtr,
683  INOUT CERT_INFO *certInfoPtr,
684  const CRYPT_HANDLE iCryptHandle )
685  {
686  int status;
687 
688  assert( isWritePtr( crmfRequestInfoPtr, sizeof( CERT_INFO ) ) );
689  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
690 
691  REQUIRES( crmfRequestInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT );
692  REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
693  certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
694  certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
695 
696  status = copyDN( &crmfRequestInfoPtr->subjectName,
697  certInfoPtr->subjectName );
698  if( cryptStatusError( status ) )
699  return( status );
700  if( crmfRequestInfoPtr->iPubkeyContext == CRYPT_ERROR && \
701  crmfRequestInfoPtr->publicKeyInfo == NULL )
702  {
703  /* Only copy the key across if a key hasn't already been added
704  earlier as CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO. Checking for
705  this special case (rather than returning an error) allows the DN
706  information from an existing certificate to be copied into a
707  request for a new key */
708  status = copyPublicKeyInfo( crmfRequestInfoPtr, iCryptHandle, NULL );
709  }
710  if( cryptStatusOK( status ) )
711  {
712  /* We copy the attributes across after the DN because that copy is
713  the hardest to undo: If there are already attributes present then
714  the copied attributes will be mixed in among them so it's not
715  really possible to undo the copy later without performing a
716  complex selective delete */
717  status = copyCRMFRequestAttributes( &crmfRequestInfoPtr->attributes,
718  certInfoPtr->attributes );
719  }
720  if( cryptStatusError( status ) )
721  deleteDN( &crmfRequestInfoPtr->subjectName );
722 
723  return( status );
724  }
725 
726 /* Copy across the issuer and subject DN and serial number */
727 
728 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
729 static int copyCertToRevRequest( INOUT CERT_INFO *crmfRevRequestInfoPtr,
730  INOUT CERT_INFO *certInfoPtr )
731  {
732  int status;
733 
734  assert( isWritePtr( crmfRevRequestInfoPtr, sizeof( CERT_INFO ) ) );
735  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
736 
737  REQUIRES( crmfRevRequestInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION );
738  REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
739  certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
740  certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
741 
742  /* If the information is already present then we can't add it again */
743  if( crmfRevRequestInfoPtr->issuerName != NULL )
744  {
745  setErrorInfo( crmfRevRequestInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
747  return( CRYPT_ERROR_INITED );
748  }
749 
750  /* Copy across the issuer name and allocate the storage that we need to
751  copy the subject name. We don't care about any internal structure of
752  the DNs so we just copy the pre-encoded form, we could in theory copy
753  the full DN but it isn't really the issuer (creator) of the object so
754  it's better if it appears to have no issuer DN than a misleading one */
755  status = copyIssuerDnData( crmfRevRequestInfoPtr, certInfoPtr );
756  if( cryptStatusError( status ) )
757  return( status );
758  status = setSerialNumber( crmfRevRequestInfoPtr,
759  certInfoPtr->cCertCert->serialNumber,
760  certInfoPtr->cCertCert->serialNumberLength );
761  if( cryptStatusOK( status ) && \
762  ( crmfRevRequestInfoPtr->subjectDNdata = \
763  clAlloc( "copyCertToRevRequest",
764  certInfoPtr->subjectDNsize ) ) == NULL )
765  status = CRYPT_ERROR_MEMORY;
766  if( cryptStatusError( status ) )
767  {
768  clFree( "copyCertToRevRequest",
769  crmfRevRequestInfoPtr->issuerDNdata );
770  crmfRevRequestInfoPtr->issuerDNptr = \
771  crmfRevRequestInfoPtr->issuerDNdata = NULL;
772  crmfRevRequestInfoPtr->issuerDNsize = 0;
773  if( crmfRevRequestInfoPtr->cCertCert->serialNumber != NULL && \
774  crmfRevRequestInfoPtr->cCertCert->serialNumber != \
775  crmfRevRequestInfoPtr->cCertCert->serialNumberBuffer )
776  {
777  clFree( "copyCertToRevRequest",
778  crmfRevRequestInfoPtr->cCertCert->serialNumber );
779  }
780  crmfRevRequestInfoPtr->cCertCert->serialNumber = NULL;
781  return( status );
782  }
783 
784  /* Copy the subject DN for use in CMP */
785  memcpy( crmfRevRequestInfoPtr->subjectDNdata, certInfoPtr->subjectDNptr,
786  certInfoPtr->subjectDNsize );
787  crmfRevRequestInfoPtr->subjectDNptr = crmfRevRequestInfoPtr->subjectDNdata;
788  crmfRevRequestInfoPtr->subjectDNsize = certInfoPtr->subjectDNsize;
789 
790  return( CRYPT_OK );
791  }
792 #endif /* USE_CERTREQ */
793 
794 /****************************************************************************
795 * *
796 * Copy Certificate Revocation Data *
797 * *
798 ****************************************************************************/
799 
800 #ifdef USE_CERTREV
801 
802 /* The OCSP ID doesn't contain any usable fields so we pre-encode it when
803  the certificate is added to the OCSP request and treat it as a blob
804  thereafter */
805 
806 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
807 static int writeOCSPID( INOUT STREAM *stream,
808  const CERT_INFO *certInfoPtr,
809  IN_BUFFER( issuerKeyHashLength ) \
810  const void *issuerKeyHash,
812  const int issuerKeyHashLength )
813  {
814  HASHFUNCTION_ATOMIC hashFunctionAtomic;
815  BYTE hashBuffer[ CRYPT_MAX_HASHSIZE + 8 ];
816  int hashSize;
817 
818  assert( isWritePtr( stream, sizeof( STREAM ) ) );
819  assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
820  assert( isReadPtr( issuerKeyHash, issuerKeyHashLength ) );
821 
822  REQUIRES( issuerKeyHashLength == KEYID_SIZE );
823  REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
824  certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
825  certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
826  REQUIRES( certInfoPtr->issuerDNptr != NULL );
827  REQUIRES( certInfoPtr->cCertCert->serialNumber != NULL );
828 
829  /* Get the issuerName hash */
830  getHashAtomicParameters( CRYPT_ALGO_SHA1, 0, &hashFunctionAtomic,
831  &hashSize );
833  certInfoPtr->issuerDNptr,
834  certInfoPtr->issuerDNsize );
835 
836  /* Write the request data */
837  writeSequence( stream,
839  sizeofObject( hashSize ) + sizeofObject( hashSize ) + \
840  sizeofInteger( certInfoPtr->cCertCert->serialNumber,
841  certInfoPtr->cCertCert->serialNumberLength ) );
842  writeAlgoID( stream, CRYPT_ALGO_SHA1 );
843  writeOctetString( stream, hashBuffer, hashSize, DEFAULT_TAG );
844  writeOctetString( stream, issuerKeyHash, issuerKeyHashLength,
845  DEFAULT_TAG );
846  return( writeInteger( stream, certInfoPtr->cCertCert->serialNumber,
847  certInfoPtr->cCertCert->serialNumberLength,
848  DEFAULT_TAG ) );
849  }
850 
851 /* Copy revocation information from an OCSP request to a response */
852 
853 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
854 static int copyOcspReqToResp( INOUT CERT_INFO *certInfoPtr,
855  INOUT CERT_INFO *ocspRequestInfoPtr )
856  {
857  int status;
858 
859  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
860  assert( isWritePtr( ocspRequestInfoPtr, sizeof( CERT_INFO ) ) );
861 
862  REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE );
863  REQUIRES( ocspRequestInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST );
864 
865  /* Copy the revocation information and extensions */
866  status = copyRevocationEntries( &certInfoPtr->cCertRev->revocations,
867  ocspRequestInfoPtr->cCertRev->revocations );
868  if( cryptStatusOK( status ) )
869  status = copyOCSPRequestAttributes( &certInfoPtr->attributes,
870  ocspRequestInfoPtr->attributes );
871  if( cryptStatusError( status ) )
872  return( status );
873 
874  return( CRYPT_OK );
875  }
876 
877 /* Copy the certificate information to the revocation list. First we make
878  sure that the CA certificate hash (needed for OCSP's weird certificate
879  ID) is present. We add the necessary information as a pre-encoded blob
880  since we can't do much with the ID fields */
881 
882 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
883 static int copyCertToOCSPRequest( INOUT CERT_INFO *ocspRequestInfoPtr,
884  INOUT CERT_INFO *certInfoPtr )
885  {
886  CERT_REV_INFO *revInfoPtr = ocspRequestInfoPtr->cCertRev;
887  STREAM stream;
888  DYNBUF essCertDB;
889  BYTE idBuffer[ 256 + 8 ], *idBufPtr = idBuffer;
890  int idLength = DUMMY_INIT, status;
891 
892  assert( isWritePtr( ocspRequestInfoPtr, sizeof( CERT_INFO ) ) );
893  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
894 
895  REQUIRES( ocspRequestInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST );
896  REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
897  certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
898  certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
899 
900  /* Make sure that there's a CA certificate hash present */
901  if( !ocspRequestInfoPtr->certHashSet )
902  {
903  setErrorInfo( ocspRequestInfoPtr, CRYPT_CERTINFO_CACERTIFICATE,
905  return( CRYPT_ERROR_NOTINITED );
906  }
907 
908  /* Generate the OCSP certificate ID */
909  sMemNullOpen( &stream );
910  status = writeOCSPID( &stream, certInfoPtr,
911  ocspRequestInfoPtr->certHash, KEYID_SIZE );
912  if( cryptStatusOK( status ) )
913  idLength = stell( &stream );
914  sMemClose( &stream );
915  if( cryptStatusError( status ) )
916  return( status );
917  if( idLength > 256 )
918  {
919  /* Allocate a buffer for an oversize ID */
920  if( ( idBufPtr = clDynAlloc( "copyCertToOCSPRequest", \
921  idLength ) ) == NULL )
922  return( CRYPT_ERROR_MEMORY );
923  }
924  sMemOpen( &stream, idBufPtr, idLength );
925  status = writeOCSPID( &stream, certInfoPtr,
926  ocspRequestInfoPtr->certHash, KEYID_SIZE );
927  sMemDisconnect( &stream );
928  if( cryptStatusOK( status ) )
929  {
930  status = addRevocationEntry( &revInfoPtr->revocations,
931  &revInfoPtr->currentRevocation,
932  CRYPT_KEYID_NONE, idBufPtr,
933  idLength, FALSE );
934  }
935  if( idBufPtr != idBuffer )
936  clFree( "copyCertToOCSPRequest", idBufPtr );
937  if( status == CRYPT_ERROR_DUPLICATE )
938  {
939  /* If this certificate is already present in the list, set the
940  extended error code for it */
941  setErrorInfo( ocspRequestInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
943  }
944  if( cryptStatusError( status ) )
945  return( status );
946 
947  /* Add the certificate information again as an ESSCertID extension to
948  work around the problems inherent in OCSP IDs */
949  status = dynCreate( &essCertDB, certInfoPtr->objectHandle,
950  CRYPT_IATTRIBUTE_ESSCERTID );
951  if( cryptStatusOK( status ) )
952  {
955 
956  /* Since this isn't a critical extension (the ESSCertID is just a
957  backup for the main, albeit not very useful, ID) we continue if
958  there's a problem adding it */
959  ( void ) addAttributeFieldString( \
960  &revInfoPtr->currentRevocation->attributes,
962  CRYPT_ATTRIBUTE_NONE, dynData( essCertDB ),
963  dynLength( essCertDB ), ATTR_FLAG_NONE,
964  &dummy1, &dummy2 );
965  dynDestroy( &essCertDB );
966  }
967  return( CRYPT_OK );
968  }
969 
970 /* Get the hash of the public key (for an OCSP request), possibly
971  overwriting a previous hash if there are multiple entries in the
972  request */
973 
974 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
975 static int copyCaCertToOCSPReq( INOUT CERT_INFO *certInfoPtr,
976  INOUT CERT_INFO *caCertInfoPtr )
977  {
978  HASHFUNCTION_ATOMIC hashFunctionAtomic;
979  STREAM stream;
980  void *dataPtr = DUMMY_INIT_PTR;
981  int length, status;
982 
983  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
984  assert( isWritePtr( caCertInfoPtr, sizeof( CERT_INFO ) ) );
985 
986  REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST );
987  REQUIRES( caCertInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
988  caCertInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
989  REQUIRES( caCertInfoPtr->publicKeyInfo != NULL );
990 
991  getHashAtomicParameters( CRYPT_ALGO_SHA1, 0, &hashFunctionAtomic, NULL );
992 
993  /* Dig down into the encoded key data to find the weird bits of key that
994  OCSP requires us to hash. We store the result as the certificate
995  hash, this is safe because this value isn't used for an OCSP request
996  so it can't be accessed externally */
997  sMemConnect( &stream, caCertInfoPtr->publicKeyInfo,
998  caCertInfoPtr->publicKeyInfoSize );
999  readSequence( &stream, NULL ); /* Wrapper */
1000  readUniversal( &stream ); /* AlgoID */
1001  status = readBitStringHole( &stream, &length, 16, DEFAULT_TAG );
1002  if( cryptStatusOK( status ) ) /* BIT STRING wrapper */
1003  status = sMemGetDataBlock( &stream, &dataPtr, length );
1004  if( cryptStatusError( status ) )
1005  {
1006  /* There's a problem with the format of the key */
1007  DEBUG_DIAG(( "Invalid certificate data format when hashing "
1008  "certificate to create OCSP ID" ));
1009  assert( DEBUG_WARN );
1010  sMemDisconnect( &stream );
1013  return( CRYPT_ERROR_INVALID );
1014  }
1015  hashFunctionAtomic( certInfoPtr->certHash, KEYID_SIZE, dataPtr, length );
1016  certInfoPtr->certHashSet = TRUE;
1017  sMemDisconnect( &stream );
1018 
1019  return( CRYPT_OK );
1020  }
1021 #endif /* USE_CERTREV */
1022 
1023 /****************************************************************************
1024 * *
1025 * Copy Certificate Validation Data *
1026 * *
1027 ****************************************************************************/
1028 
1029 #ifdef USE_CERTVAL
1030 
1031 /* Copy validity information from an RTCS request to a response */
1032 
1033 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1034 static int copyRtcsReqToResp( INOUT CERT_INFO *certInfoPtr,
1035  INOUT CERT_INFO *rtcsRequestInfoPtr )
1036  {
1037  int status;
1038 
1039  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1040  assert( isWritePtr( rtcsRequestInfoPtr, sizeof( CERT_INFO ) ) );
1041 
1042  REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_RTCS_RESPONSE );
1043  REQUIRES( rtcsRequestInfoPtr->type == CRYPT_CERTTYPE_RTCS_REQUEST );
1044 
1045  /* Copy the certificate validity information and extensions */
1046  status = copyValidityEntries( &certInfoPtr->cCertVal->validityInfo,
1047  rtcsRequestInfoPtr->cCertVal->validityInfo );
1048  if( cryptStatusOK( status ) )
1049  status = copyRTCSRequestAttributes( &certInfoPtr->attributes,
1050  rtcsRequestInfoPtr->attributes );
1051  return( status );
1052  }
1053 
1054 /* Copy the certificate hash. We read the value indirectly since it's
1055  computed on demand and may not have been evaluated yet */
1056 
1057 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1058 static int copyCertToRTCSRequest( INOUT CERT_INFO *rtcsRequestInfoPtr,
1059  INOUT CERT_INFO *certInfoPtr )
1060  {
1061  CERT_VAL_INFO *valInfoPtr = rtcsRequestInfoPtr->cCertVal;
1062  BYTE certHash[ CRYPT_MAX_HASHSIZE + 8 ];
1063  int certHashLength, status;
1064 
1065  assert( isWritePtr( rtcsRequestInfoPtr, sizeof( CERT_INFO ) ) );
1066  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1067 
1068  REQUIRES( rtcsRequestInfoPtr->type == CRYPT_CERTTYPE_RTCS_REQUEST );
1069  REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
1070  certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
1071  certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
1072 
1073  status = getCertComponentString( certInfoPtr,
1075  certHash, CRYPT_MAX_HASHSIZE,
1076  &certHashLength );
1077  if( cryptStatusOK( status ) )
1078  {
1079  status = addValidityEntry( &valInfoPtr->validityInfo,
1080  &valInfoPtr->currentValidity,
1081  certHash, certHashLength );
1082  }
1083  if( status == CRYPT_ERROR_DUPLICATE )
1084  {
1085  /* If this certificate is already present in the list, set the
1086  extended error code for it */
1087  setErrorInfo( rtcsRequestInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
1089  }
1090  return( status );
1091  }
1092 #endif /* USE_CERTVAL */
1093 
1094 /****************************************************************************
1095 * *
1096 * Copy PKI User Data *
1097 * *
1098 ****************************************************************************/
1099 
1100 #ifdef USE_PKIUSER
1101 
1102 /* Set or modify data in a certificate request based on the PKI user
1103  information. This is rather more complicated than the standard copy
1104  operations because we potentially have to merge information already
1105  present in the request with information in the PKI user object, checking
1106  for consistency/conflicts in the process.
1107 
1108  The attributes that can be specified in requests are severely limited
1109  (see the long comment for sanitiseCertAttributes() in comp_set.c) so
1110  the only ones that we really need to handle are the altName and a special-
1111  case keyUsage check for CA key usages, along with special handling for
1112  the SCEP challenge password (see the comment in the code below) */
1113 
1114 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1115 static int copyPkiUserAttributes( INOUT CERT_INFO *certInfoPtr,
1116  INOUT ATTRIBUTE_PTR *pkiUserAttributes )
1117  {
1118  ATTRIBUTE_PTR *requestAttrPtr, *pkiUserAttrPtr;
1119  int value, status;
1120 
1121  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1122  assert( isWritePtr( pkiUserAttributes, sizeof( ATTRIBUTE_LIST ) ) );
1123 
1124  REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTREQUEST || \
1125  certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT );
1126 
1127  /* If there are altNames present in both the PKI user data and the
1128  request, make sure that they match */
1129  requestAttrPtr = findAttribute( certInfoPtr->attributes,
1131  pkiUserAttrPtr = findAttribute( pkiUserAttributes,
1133  if( requestAttrPtr != NULL && pkiUserAttrPtr != NULL )
1134  {
1135  /* Both the certificate request and the PKI user have altNames,
1136  make sure that they're identical */
1137  if( !compareAttribute( requestAttrPtr, pkiUserAttrPtr ) )
1138  {
1141  return( CRYPT_ERROR_INVALID );
1142  }
1143 
1144  /* The two altNames are identical, delete the one in the request to
1145  allow the one from the PKI user data to be copied across */
1146  status = deleteAttribute( &certInfoPtr->attributes,
1147  &certInfoPtr->attributeCursor,
1148  requestAttrPtr,
1149  certInfoPtr->currentSelection.dnPtr );
1150  if( cryptStatusError( status ) )
1151  return( status );
1152  }
1153 
1154  /* There's one rather ugly special-case situation that we have to handle
1155  which is when the user has submitted a PnP PKI request for a generic
1156  signing certificate but their PKI user information indicates that
1157  they're intended to be a CA user. The processing flow for this is:
1158 
1159  Read request data from an external source into certificate
1160  request object, creating a state=high object;
1161 
1162  Add PKI user information to state=high request;
1163 
1164  When augmenting the request with the PKI user information the
1165  incoming request will contain a keyUsage of digitalSignature while
1166  the PKI user information will contain a keyUsage of keyCertSign
1167  and/or crlSign. We can't fix this up at the PnP processing level
1168  because the request object will be in the high state once it's
1169  instantiated and no changes to the attributes can be made (the PKI
1170  user information is a special case that can be added to an object in
1171  the high state but which modifies attributes in it as if it were
1172  still in the low state).
1173 
1174  To avoid the attribute conflict, if we find this situation in the
1175  request/pkiUser combination we delete the keyUsage in the request to
1176  allow it to be replaced by the pkiUser keyUsage. Hardcoding in this
1177  special case isn't very elegant but it's the only way to make the PnP
1178  PKI issue work without requiring that the user explicitly specify
1179  that they want to be a CA in the request's keyUsage, which makes it
1180  rather non-PnP and would also lead to slightly strange requests since
1181  basicConstraints can't be specified in requests while the CA keyUsage
1182  can */
1183  status = getAttributeFieldValue( certInfoPtr->attributes,
1185  CRYPT_ATTRIBUTE_NONE, &value );
1186  if( cryptStatusOK( status ) && value == CRYPT_KEYUSAGE_DIGITALSIGNATURE )
1187  {
1188  status = getAttributeFieldValue( pkiUserAttributes,
1190  CRYPT_ATTRIBUTE_NONE, &value );
1191  if( cryptStatusOK( status ) && ( value & KEYUSAGE_CA ) )
1192  {
1193  /* The certificate contains a digitalSignature keyUsage and the
1194  PKI user information contains a CA usage, delete the
1195  certificate's keyUsage to make way for the PKI user's CA
1196  keyUsage */
1197  status = deleteCompleteAttribute( &certInfoPtr->attributes,
1198  &certInfoPtr->attributeCursor,
1200  certInfoPtr->currentSelection.dnPtr );
1201  if( cryptStatusError( status ) )
1202  return( status );
1203  }
1204  }
1205 
1206  /* Copy the attributes from the PKI user information into the
1207  certificate */
1208  status = copyAttributes( &certInfoPtr->attributes, pkiUserAttributes,
1209  &certInfoPtr->errorLocus,
1210  &certInfoPtr->errorType );
1211  if( cryptStatusError( status ) )
1212  return( status );
1213 
1214  /* There's another special that we have to handle which occurs for the
1215  SCEP challenge password, which the SCEP protocol requires to be
1216  placed in the PKCS #10 request instead of being included in the SCEP
1217  metadata. This shouldn't be copied across to the certificate since
1218  the NOCOPY flag is set for the attribute, but to make absolutely
1219  certain we try and delete it anyway. Since this could in theory be
1220  present in non-SCEP requests as well (the request-processing code
1221  just knows about PKCS #10 requests as a whole, not requests from a
1222  SCEP source vs. requests not from a SCEP source), we make the delete
1223  unconditional */
1224  if( findAttributeField( certInfoPtr->attributes,
1226  CRYPT_ATTRIBUTE_NONE ) != NULL )
1227  {
1228  status = deleteCompleteAttribute( &certInfoPtr->attributes,
1229  &certInfoPtr->attributeCursor,
1231  certInfoPtr->currentSelection.dnPtr );
1232  if( cryptStatusError( status ) )
1233  return( status );
1234  }
1235 
1236  /* The PKI user information contains an sKID that's used to uniquely
1237  identify the user, this applies to the user information itself rather
1238  than the certificate that'll be issued from it. Since this will have
1239  been copied over alongside the other attributes we need to explicitly
1240  delete it before we continue */
1241  if( findAttributeField( certInfoPtr->attributes,
1243  CRYPT_ATTRIBUTE_NONE ) != NULL )
1244  {
1245  status = deleteCompleteAttribute( &certInfoPtr->attributes,
1246  &certInfoPtr->attributeCursor,
1248  certInfoPtr->currentSelection.dnPtr );
1249  if( cryptStatusError( status ) )
1250  return( status );
1251  }
1252 
1253  return( CRYPT_OK );
1254  }
1255 
1256 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
1257 static int assemblePkiUserDN( INOUT CERT_INFO *certInfoPtr,
1258  const DN_PTR *pkiUserSubjectName,
1259  IN_BUFFER( commonNameLength ) const void *commonName,
1260  IN_LENGTH_SHORT const int commonNameLength )
1261  {
1262  STREAM stream;
1263  void *tempDN = NULL, *tempDNdata;
1264  int tempDNsize = DUMMY_INIT, status;
1265 
1266  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1267  assert( isReadPtr( commonName, commonNameLength ) );
1268 
1269  REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT );
1270  REQUIRES( pkiUserSubjectName != NULL );
1271  REQUIRES( commonNameLength > 0 && \
1272  commonNameLength < MAX_INTLENGTH_SHORT );
1273 
1274  /* Copy the DN template, append the user-supplied CN, and allocate room
1275  for the encoded form */
1276  status = copyDN( &tempDN, pkiUserSubjectName );
1277  if( cryptStatusError( status ) )
1278  return( status );
1279  status = insertDNComponent( &tempDN, CRYPT_CERTINFO_COMMONNAME,
1280  commonName, commonNameLength,
1281  &certInfoPtr->errorType );
1282  if( cryptStatusOK( status ) )
1283  status = tempDNsize = sizeofDN( tempDN );
1284  if( cryptStatusError( status ) )
1285  {
1286  deleteDN( &tempDN );
1287  return( status );
1288  }
1289  if( ( tempDNdata = clAlloc( "assemblePkiUserDN", tempDNsize ) ) == NULL )
1290  {
1291  deleteDN( &tempDN );
1292  return( CRYPT_ERROR_MEMORY );
1293  }
1294 
1295  /* Replace the existing DN with the new one and set up the encoded
1296  form. At this point we could already have an encoded DN present if
1297  the request was read from encoded form, with the subject DN pointer
1298  pointing into the encoded request data (if the request was created
1299  from scratch then there's no DN present). We replace the (possible)
1300  existing pointer into the certificate data with a pointer to the
1301  updated encoded DN written to our newly-allocated block of memory */
1302  deleteDN( &certInfoPtr->subjectName );
1303  certInfoPtr->subjectName = tempDN;
1304  sMemOpen( &stream, tempDNdata, tempDNsize );
1305  status = writeDN( &stream, tempDN, DEFAULT_TAG );
1306  ENSURES( cryptStatusOK( status ) );
1307  sMemDisconnect( &stream );
1308  certInfoPtr->subjectDNdata = certInfoPtr->subjectDNptr = tempDNdata;
1309  certInfoPtr->subjectDNsize = tempDNsize;
1310 
1311  return( CRYPT_OK );
1312  }
1313 
1314 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1315 static int copyPkiUserToCertReq( INOUT CERT_INFO *certInfoPtr,
1316  INOUT CERT_INFO *pkiUserInfoPtr )
1317  {
1318  CRYPT_ATTRIBUTE_TYPE dnComponentType;
1319  DN_PTR *requestDNSubset, *pkiUserDNSubset;
1321  int dummy, status;
1322 
1323  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1324  assert( isWritePtr( pkiUserInfoPtr, sizeof( CERT_INFO ) ) );
1325 
1326  REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTREQUEST || \
1327  certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT );
1328  REQUIRES( pkiUserInfoPtr->type == CRYPT_CERTTYPE_PKIUSER );
1329  REQUIRES( pkiUserInfoPtr->certificate != NULL );
1330 
1331  /* Because a DN can be made up of elements from both the certificate
1332  request and the PKI user information, it's possible that neither can
1333  contain a DN, expecting it to be supplied by the other side.
1334  Although the lack of a DN would be caught anyway when the certificate
1335  is signed, it's better to alert the caller at this early stage rather
1336  than later on in the certification process. First we check for an
1337  overall missing DN and then for the more specific case of a missing
1338  CN.
1339 
1340  Note that both here and in all of the following checks we return an
1341  error status of CRYPT_ERROR_INVALID rather than CRYPT_ERROR_NOTINITED
1342  since this is a validity check of the certificate request against the
1343  PKI user information and not a general object-ready-to-encode check */
1344  if( certInfoPtr->subjectName == NULL && \
1345  pkiUserInfoPtr->subjectName == NULL )
1346  {
1349  return( CRYPT_ERROR_INVALID );
1350  }
1351  if( ( certInfoPtr->subjectName == NULL || \
1352  cryptStatusError( \
1353  getDNComponentValue( certInfoPtr->subjectName,
1354  CRYPT_CERTINFO_COMMONNAME, 0, NULL, 0,
1355  &dummy ) ) ) && \
1356  ( pkiUserInfoPtr->subjectName == NULL || \
1357  cryptStatusError( \
1358  getDNComponentValue( pkiUserInfoPtr->subjectName,
1359  CRYPT_CERTINFO_COMMONNAME, 0, NULL, 0,
1360  &dummy ) ) ) )
1361  {
1364  return( CRYPT_ERROR_INVALID );
1365  }
1366 
1367  /* If there's no DN present in the request then one has been supplied by
1368  the CA in the PKI user information, copy over the DN and its encoded
1369  form from the user information */
1370  if( certInfoPtr->subjectName == NULL )
1371  {
1372  status = copyDN( &certInfoPtr->subjectName,
1373  pkiUserInfoPtr->subjectName );
1374  if( cryptStatusError( status ) )
1375  return( status );
1376  ENSURES( pkiUserInfoPtr->subjectDNptr != NULL );
1377  if( ( certInfoPtr->subjectDNdata = \
1378  clAlloc( "copyPkiUserToCertReq",
1379  pkiUserInfoPtr->subjectDNsize ) ) == NULL )
1380  {
1381  deleteDN( &certInfoPtr->subjectName );
1382  return( CRYPT_ERROR_MEMORY );
1383  }
1384  memcpy( certInfoPtr->subjectDNdata, pkiUserInfoPtr->subjectDNptr,
1385  pkiUserInfoPtr->subjectDNsize );
1386  certInfoPtr->subjectDNptr = certInfoPtr->subjectDNdata;
1387  certInfoPtr->subjectDNsize = pkiUserInfoPtr->subjectDNsize;
1388 
1389  /* Copy any additional attributes across */
1390  return( copyPkiUserAttributes( certInfoPtr,
1391  pkiUserInfoPtr->attributes ) );
1392  }
1393 
1394  /* If there's no PKI user DN with the potential to conflict with the one
1395  in the request present, copy any additional attributes across and
1396  exit */
1397  if( pkiUserInfoPtr->subjectName == NULL )
1398  {
1399  ENSURES( certInfoPtr->subjectName != NULL );
1400  return( copyPkiUserAttributes( certInfoPtr,
1401  pkiUserInfoPtr->attributes ) );
1402  }
1403 
1404  /* If there are full DNs present in both objects and they match, copy
1405  any additional attributes across and exit */
1406  if( compareDN( certInfoPtr->subjectName,
1407  pkiUserInfoPtr->subjectName, FALSE, NULL ) )
1408  {
1409  return( copyPkiUserAttributes( certInfoPtr,
1410  pkiUserInfoPtr->attributes ) );
1411  }
1412 
1413  /* Now things get complicated because there are distinct request DN and
1414  PKI user DNs present and we need to reconcile the two. Typically the
1415  CA will have provided a partial DN with the user providing the rest:
1416 
1417  pkiUser: A - B - C - D
1418  request: A - B - C - D - E - F
1419 
1420  in which case we could just allow the request DN (in theory we're
1421  merging the two, but since the pkiUser DN is a proper subset of the
1422  request DN it just acts as a filter). The real problem though occurs
1423  when we get a request like:
1424 
1425  pkiUser: A - B - C - D
1426  request: X
1427 
1428  where X can be any of:
1429 
1430  'D': Legal, this duplicates a single permitted element
1431  'E': Legal, this adds a new sub-element
1432  'D - E': Legal, this duplicates a legal element and adds a new sub-
1433  element
1434  'A - B - C - D#' where 'D#' doesn't match 'D', for example it's a CN
1435  that differs from the pkiUser CN: Not legal since it violates a
1436  CA-imposed constraint.
1437  'A - B - C - D - E - F': Legal, this is the scenario given above
1438  where one is a proper subset of the other.
1439  'D - A': This is somewhat dubious and probably not legal, for
1440  example if 'A' is a countryName.
1441  'D - A - B - C - D': This is almost certainly not legal because in a
1442  hierarchy like this 'A' is probably a countryName so an attempt
1443  to merge the request DN at point 'D' in the pkiUser DN could
1444  lead to a malformed DN.
1445  'E - C - D - E': This may or may not be legal if the middle elements
1446  are things like O's and OU's, which can be mixed up arbitrarily.
1447 
1448  Handling this really requires human intervention to decide what's
1449  legal or not. In the absence of an AI capability in the software
1450  we restrict ourselves to allowing only two cases:
1451 
1452  1. If the PKI user contains a DN without a CN and the request
1453  contains only a CN (typically used where the CA provides a
1454  template for the user's DN and the user supplies only their
1455  name), we merge the CA-provided DN-without-CN with the user-
1456  provided CN.
1457 
1458  2. If the PKI user contains a DN without a CN and the request
1459  contains a full DN (a variation of the above where the user
1460  knows their full DN), we make sure that the rest of the DN
1461  matches.
1462 
1463  First we check that the user DN contains a CN, optionally preceded
1464  by a prefix of the PKI user's DN, by passing them to compareDN(),
1465  which checks whether the first DN is a proper subset of the second.
1466  Some sample DN configurations and their results are:
1467 
1468  request = CN result = FALSE, mismatchSubset = CN
1469  pkiUser = C - O - OU
1470 
1471  request = ... X result = FALSE, mismatchSubset = X
1472  pkiUser = C - O - OU
1473 
1474  request = C - O - OU - CN result = FALSE, mismatchSubset = CN
1475  pkiUser = C - O - OU
1476 
1477  request = C - O - OU - CN1 result = FALSE, mismatchSubset = CN1
1478  pkiUser = C - O - OU - CN2
1479 
1480  request = C - O - OU result = TRUE, mismatchSubset = NULL
1481  pkiUser = C - O - OU - CN
1482 
1483  The set of DNs with a prefix-match-result of TRUE (in other words the
1484  request contains a subset of the PKI user's DN) are trivially
1485  invalid, so we can reject them immediately */
1486  if( compareDN( certInfoPtr->subjectName, pkiUserInfoPtr->subjectName,
1487  TRUE, &requestDNSubset ) )
1488  {
1489  /* The issuer-constraint error is technically accurate if a little
1490  unexpected at this point, since the PKIUser information has been
1491  set as a constraint by the CA */
1494  return( CRYPT_ERROR_INVALID );
1495  }
1496  ANALYSER_HINT( requestDNSubset != NULL );
1497 
1498  /* The request DN is a prefix (possibly an empty one) of the PKI user
1499  DN, check that the mis-matching part is only a CN */
1500  status = getDNComponentInfo( requestDNSubset, &dnComponentType,
1501  &dnContinues );
1502  if( cryptStatusError( status ) )
1503  {
1504  /* This is an even more problematic situation to report (since it's
1505  a shouldn't-occur type error), the best that we can do is report
1506  a generic issuer constraint */
1509  return( CRYPT_ERROR_INVALID );
1510  }
1511  if( dnComponentType != CRYPT_CERTINFO_COMMONNAME || dnContinues )
1512  {
1513  /* Check for the special case of there being no CN at all present in
1514  the request DN, which lets us return a more specific error
1515  indicator (this is a more specific case of the check performed
1516  earlier for a CN in the request or the PKI user object) */
1517  status = getDNComponentValue( requestDNSubset,
1518  CRYPT_CERTINFO_COMMONNAME, 0, NULL, 0,
1519  &dummy );
1520  if( cryptStatusError( status ) )
1521  {
1524  return( CRYPT_ERROR_INVALID );
1525  }
1526 
1527  /* The mismatching portion of the request DN isn't just a CN */
1530  return( CRYPT_ERROR_INVALID );
1531  }
1532 
1533  /* There's one special case that we have to handle where both DNs
1534  consist of identical prefixes ending in CNs but the CNs differ, which
1535  passes the above check. We do this by reversing the order of the
1536  match performed above, if what's left is also a CN then there was a
1537  mismatch in the CNs */
1538  if( !compareDN( pkiUserInfoPtr->subjectName, certInfoPtr->subjectName,
1539  TRUE, &pkiUserDNSubset ) )
1540  {
1541  status = getDNComponentInfo( pkiUserDNSubset, &dnComponentType,
1542  &dnContinues );
1543  if( cryptStatusError( status ) || \
1544  dnComponentType == CRYPT_CERTINFO_COMMONNAME )
1545  {
1548  return( CRYPT_ERROR_INVALID );
1549  }
1550  }
1551 
1552  /* If the request DN consists only of a CN, replace the request DN with
1553  the merged DN prefix from the PKI user DN and the CN from the request
1554  DN. Otherwise, the request DN contains a full DN including a CN that
1555  matches the full PKI user DN and there's nothing to do beyond the
1556  checks that we've already performed above */
1557  if( certInfoPtr->subjectName == requestDNSubset )
1558  {
1559  char commonName[ CRYPT_MAX_TEXTSIZE + 8 ];
1560  int commonNameLength;
1561 
1562  status = getDNComponentValue( requestDNSubset,
1564  commonName, CRYPT_MAX_TEXTSIZE,
1565  &commonNameLength );
1566  if( cryptStatusOK( status ) )
1567  status = assemblePkiUserDN( certInfoPtr,
1568  pkiUserInfoPtr->subjectName,
1569  commonName, commonNameLength );
1570  if( cryptStatusError( status ) )
1571  return( status );
1572  }
1573 
1574  /* Copy any additional attributes across */
1575  return( copyPkiUserAttributes( certInfoPtr, pkiUserInfoPtr->attributes ) );
1576  }
1577 #endif /* USE_PKIUSER */
1578 
1579 /****************************************************************************
1580 * *
1581 * Certificate Information Copy External Interface *
1582 * *
1583 ****************************************************************************/
1584 
1585 /* Copy user certificate information into a certificate object, either a
1586  CRL, a certification/revocation request, or an RTCS/OCSP request */
1587 
1588 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1589 static int copyUserCertInfo( INOUT CERT_INFO *certInfoPtr,
1590  INOUT CERT_INFO *userCertInfoPtr,
1591  IN_HANDLE const CRYPT_HANDLE iCryptHandle )
1592  {
1593  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1594  assert( isWritePtr( userCertInfoPtr, sizeof( CERT_INFO ) ) );
1595 
1596  REQUIRES( isHandleRangeValid( iCryptHandle ) );
1597  REQUIRES( userCertInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
1598  userCertInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
1599  REQUIRES( userCertInfoPtr->certificate != NULL );
1600 
1601  /* If it's an RTCS or OCSP request, remember the responder URL if there's
1602  one present. We can't leave it to be read out of the certificate
1603  because authorityInfoAccess isn't a valid attribute for RTCS/OCSP
1604  requests */
1605 #ifdef USE_CERTREV
1606  if( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST && \
1607  certInfoPtr->cCertRev->responderUrl == NULL )
1608  {
1609  int status;
1610 
1611  status = copyResponderURL( certInfoPtr, userCertInfoPtr );
1612  if( cryptStatusError( status ) )
1613  return( status );
1614  }
1615 #endif /* USE_CERTREV */
1616 #ifdef USE_CERTVAL
1617  if( certInfoPtr->type == CRYPT_CERTTYPE_RTCS_REQUEST && \
1618  certInfoPtr->cCertVal->responderUrl == NULL )
1619  {
1620  int status;
1621 
1622  status = copyResponderURL( certInfoPtr, userCertInfoPtr );
1623  if( cryptStatusError( status ) )
1624  return( status );
1625  }
1626 #endif /* USE_CERTVAL */
1627 
1628  /* Copy the required information across to the certificate */
1629  switch( certInfoPtr->type )
1630  {
1631 #ifdef USE_CERTREQ
1633  return( copyCertToRequest( certInfoPtr, userCertInfoPtr,
1634  iCryptHandle ) );
1635 
1637  return( copyCertToRevRequest( certInfoPtr, userCertInfoPtr ) );
1638 #endif /* USE_CERTREQ */
1639 
1640 #ifdef USE_CERTREV
1641  case CRYPT_CERTTYPE_CRL:
1642  return( copyRevocationInfo( certInfoPtr, userCertInfoPtr ) );
1643 
1645  return( copyCertToOCSPRequest( certInfoPtr, userCertInfoPtr ) );
1646 #endif /* USE_CERTREV */
1647 
1648 #ifdef USE_CERTVAL
1650  return( copyCertToRTCSRequest( certInfoPtr, userCertInfoPtr ) );
1651 #endif /* USE_CERTVAL */
1652  }
1653 
1654  retIntError();
1655  }
1656 
1657 /* A general dispatch function for copying information from one certificate
1658  object to another. This is a wrapper that acquires the source object's
1659  data and then passes a pointer to it to the actual copy function that
1660  copies any necessary information to the destination object, releasing the
1661  source object after the copy */
1662 
1663 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
1664 int copyCertObject( INOUT CERT_INFO *certInfoPtr,
1667  IN const int certInfo )
1668  {
1669  CERT_INFO *addedCertInfoPtr;
1670  int status;
1671 
1672  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1673 
1674  REQUIRES( isAttribute( certInfoType ) || \
1675  isInternalAttribute( certInfoType ) );
1676  REQUIRES( isHandleRangeValid( addedCert ) );
1677 
1678  status = krnlAcquireObject( addedCert, OBJECT_TYPE_CERTIFICATE,
1679  ( void ** ) &addedCertInfoPtr,
1681  if( cryptStatusError( status ) )
1682  return( status );
1683  switch( certInfoType )
1684  {
1686  status = copyUserCertInfo( certInfoPtr, addedCertInfoPtr,
1687  certInfo );
1688  break;
1689 
1690 #ifdef USE_CERTREV
1692  status = copyCaCertToOCSPReq( certInfoPtr, addedCertInfoPtr );
1693  break;
1694 #endif /* USE_CERTREV */
1695 
1696 #ifdef USE_CERTREQ
1698  status = copyCertReqToCert( certInfoPtr, addedCertInfoPtr );
1699  break;
1700 #endif /* USE_CERTREQ */
1701 
1702 #ifdef USE_CERTVAL
1703  case CRYPT_IATTRIBUTE_RTCSREQUEST:
1704  status = copyRtcsReqToResp( certInfoPtr, addedCertInfoPtr );
1705  break;
1706 #endif /* USE_CERTVAL */
1707 
1708 #ifdef USE_CERTREV
1709  case CRYPT_IATTRIBUTE_OCSPREQUEST:
1710  status = copyOcspReqToResp( certInfoPtr, addedCertInfoPtr );
1711  break;
1712 
1713  case CRYPT_IATTRIBUTE_REVREQUEST:
1714  status = copyRevReqToCert( certInfoPtr, addedCertInfoPtr );
1715  break;
1716 #endif /* USE_CERTREV */
1717 
1718 #ifdef USE_PKIUSER
1719  case CRYPT_IATTRIBUTE_PKIUSERINFO:
1720  status = copyPkiUserToCertReq( certInfoPtr, addedCertInfoPtr );
1721  break;
1722 #endif /* USE_PKIUSER */
1723 
1724  case CRYPT_IATTRIBUTE_BLOCKEDATTRS:
1725  status = sanitiseCertAttributes( certInfoPtr,
1726  addedCertInfoPtr->attributes );
1727  break;
1728 
1729  default:
1730  retIntError();
1731  }
1732  krnlReleaseObject( addedCertInfoPtr->objectHandle );
1733  return( status );
1734  }
1735 #endif /* USE_CERTIFICATES */