cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
comp_get.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Get/Delete Certificate Components *
4 * Copyright Peter Gutmann 1997-2009 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "cert.h"
10  #include "asn1.h"
11  #include "asn1_ext.h"
12 #else
13  #include "cert/cert.h"
14  #include "enc_dec/asn1.h"
15  #include "enc_dec/asn1_ext.h"
16 #endif /* Compiler-specific includes */
17 
18 #ifdef USE_CERTIFICATES
19 
20 /****************************************************************************
21 * *
22 * Get Certificate Information *
23 * *
24 ****************************************************************************/
25 
26 /* Find an attribute in an attribute list, either in the overall certificate
27  object attribute list or a per-entry attribute list. This can also
28  return entries with two special-case properties:
29 
30  ATTRIBUTE_PROPERTY_DEFAULTVALUE: The field has a default value and isn't
31  present in the list, but some other field in the same attribute is
32  present. For example if CRYPT_CERTINFO_ISSUINGDIST_FULLNAME were
33  present in the attribute list than an attempt to read
34  CRYPT_CERTINFO_ISSUINGDIST_INDIRECTCRL, which is declared 'DEFAULT
35  FALSE', would return an entry with this property.
36 
37  ATTRIBUTE_PROPERTY_COMPLETEATTRIBUTE: The field os an identifier for a
38  complete attribute, e.g. CRYPT_CERTINFO_AUTHORITYINFOACCESS, for
39  which only the individual CRYPT_CERTINFO_AUTHORITYINFO_xyz fields
40  can be present */
41 
43 ATTRIBUTE_PTR *findAttributeComponent( const CERT_INFO *certInfoPtr,
44  IN_ATTRIBUTE \
46  {
47 #ifdef USE_CERTREV
49  REVOCATION_INFO *currentRevocation;
50 #endif /* USE_CERTREV */
51 
52  assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
53 
54  REQUIRES_N( certInfoType > CRYPT_ATTRIBUTE_NONE && \
55  certInfoType < CRYPT_ATTRIBUTE_LAST );
56 
57  /* If it's just a general certificate attribute, return it to the
58  caller */
59  if( !isRevocationEntryComponent( certInfoType ) )
60  return( findAttributeFieldEx( certInfoPtr->attributes,
61  certInfoType ) );
62 
63 #ifdef USE_CERTVAL
64  /* It's a per-entry attribute, if it's an RTCS per-entry attribute get
65  the attribute from the currently selected entry */
66  if( certInfoPtr->type == CRYPT_CERTTYPE_RTCS_REQUEST || \
67  certInfoPtr->type == CRYPT_CERTTYPE_RTCS_RESPONSE )
68  {
69  VALIDITY_INFO *currentValidity = certInfoPtr->cCertVal->currentValidity;
70 
71  if( currentValidity == NULL )
72  return( NULL );
73  return( findAttributeFieldEx( currentValidity->attributes,
74  certInfoType ) );
75  }
76 #endif /* USE_CERTVAL */
77 
78 #ifdef USE_CERTREV
79  /* It's a CRL or OCSP per-entry attribute, get the attribute from the
80  currently selected entry */
81  currentRevocation = certInfoPtr->cCertRev->currentRevocation;
82  if( currentRevocation == NULL )
83  return( NULL );
84  attributePtr = findAttributeFieldEx( currentRevocation->attributes,
85  certInfoType );
86  if( attributePtr == NULL && \
87  certInfoType == CRYPT_CERTINFO_CRLREASON )
88  {
89  /* Revocation reason codes are actually a single range of values
90  spread across two different extensions so if we don't find the
91  value as a straight cRLReason we try again for a cRLExtReason.
92  If we've been specifically asked for a cRLExtReason we don't go
93  the other way because the caller (presumably) specifically wants
94  the extended reason code */
95  attributePtr = findAttributeFieldEx( currentRevocation->attributes,
97  }
98 
99  return( attributePtr );
100 #else
101  return( NULL );
102 #endif /* USE_CERTREV */
103  }
104 
105 /* Get a certificate component */
106 
107 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
108 static int getCertAttributeComponent( const CERT_INFO *certInfoPtr,
109  IN_ATTRIBUTE \
110  const CRYPT_ATTRIBUTE_TYPE certInfoType,
111  OUT int *value )
112  {
114 
115  assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
116  assert( isWritePtr( value, sizeof( int ) ) );
117 
118  REQUIRES( certInfoType > CRYPT_ATTRIBUTE_NONE && \
119  certInfoType < CRYPT_ATTRIBUTE_LAST );
120 
121  /* Clear return values */
122  *value = 0;
123 
124  /* Try and find this attribute in the attribute list */
125  attributePtr = findAttributeComponent( certInfoPtr, certInfoType );
126  if( attributePtr == NULL )
127  return( CRYPT_ERROR_NOTFOUND );
128 
129  /* If this is a non-present field with a default value in an attribute
130  for which some other field is present (e.g. if we're trying to read
131  CRYPT_CERTINFO_ISSUINGDIST_USERCERTSONLY, which is declared
132  DEFAULT FALSE, and CRYPT_CERTINFO_ISSUINGDIST_FULLNAME is present)
133  then we regard any default fields in the same attribute to be
134  (pseudo)-present, so we return the default value */
135  if( checkAttributeProperty( attributePtr,
137  {
138  const int defaultValue = getDefaultFieldValue( certInfoType );
139  if( cryptStatusError( defaultValue ) )
140  return( defaultValue );
141 
142  *value = defaultValue;
143  return( CRYPT_OK );
144  }
145 
146  /* If we've been given the ID for a complete attribute (e.g.
147  CRYPT_CERTINFO_AUTHORITYINFOACCESS, for which only the individual
148  CRYPT_CERTINFO_AUTHORITYINFO_xyz fields can be present), return a
149  boolean value indicating that the overall attribute is present */
150  if( checkAttributeProperty( attributePtr,
152  {
153  *value = TRUE;
154  return( CRYPT_OK );
155  }
156 
157  /* Get the attribute component value */
158  return( getAttributeDataValue( attributePtr, value ) );
159  }
160 
161 /* Create a copy of a certificate object for external use. This is used
162  principally to sanitise internal certificate objects, for example if
163  they're attached to a private key or for internal use only. Since the
164  object can be either a standalone certificate or a complete certificate
165  chain we have to process it somewhat indirectly rather than just
166  instantiating a new certificate from the encoded certificate data.
167 
168  It's also used to convert to/from data-only certificates, for example to
169  convert from a stored data-only certificate to a full certificate capable
170  of being used for signature checking, this is easier than trying to
171  retroactively attach a public-key context to a data-only certificate */
172 
173 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
174 static int getCertCopy( const CERT_INFO *certInfoPtr,
176  const BOOLEAN isDataOnlyCert )
177  {
179  ( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE ) ? \
182  BYTE certData[ 2048 + 8 ], *certDataPtr = certData;
183  int status;
184 
185  assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
186  assert( isWritePtr( iCertCopy, sizeof( CRYPT_CERTIFICATE ) ) );
187 
188  REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
189  certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
190 
191  /* Clear return value */
192  *iCertCopy = CRYPT_ERROR;
193 
194  setMessageData( &msgData, NULL, 0 );
195  status = krnlSendMessage( certInfoPtr->objectHandle,
196  IMESSAGE_CRT_EXPORT, &msgData,
197  formatType );
198  if( cryptStatusError( status ) )
199  return( status );
200  if( msgData.length > 2048 )
201  {
202  if( ( certDataPtr = clAlloc( "getCertCopy", \
203  msgData.length + 8 ) ) == NULL )
204  return( CRYPT_ERROR_MEMORY );
205  }
206  setMessageData( &msgData, certDataPtr, msgData.length );
207  status = krnlSendMessage( certInfoPtr->objectHandle,
208  IMESSAGE_CRT_EXPORT, &msgData,
209  formatType );
210  if( cryptStatusOK( status ) )
211  {
212  MESSAGE_CREATEOBJECT_INFO createInfo;
213 
214  setMessageCreateObjectIndirectInfo( &createInfo, certDataPtr,
215  msgData.length,
216  isDataOnlyCert ? \
217  CRYPT_ICERTTYPE_DATAONLY : \
218  certInfoPtr->type );
221  &createInfo, OBJECT_TYPE_CERTIFICATE );
222  if( cryptStatusOK( status ) )
223  *iCertCopy = createInfo.cryptHandle;
224  }
225  if( certDataPtr != certData )
226  clFree( "getCertCopy", certDataPtr );
227 
228  return( status );
229  }
230 
231 /****************************************************************************
232 * *
233 * Get a Certificate Component *
234 * *
235 ****************************************************************************/
236 
237 /* Get a certificate component */
238 
239 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
240 int getCertComponent( INOUT CERT_INFO *certInfoPtr,
241  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE certInfoType,
242  OUT_INT_Z int *certInfo )
243  {
244  int status;
245 
246  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
247  assert( isWritePtr( certInfo, sizeof( int ) ) );
248 
249  REQUIRES( isAttribute( certInfoType ) || \
250  isInternalAttribute( certInfoType ) );
251 
252  /* Clear return value */
253  *certInfo = 0;
254 
255  /* If it's a GeneralName or DN component, return it. These are
256  special-case attribute values so they have to come before the
257  general attribute-handling code */
258  if( isGeneralNameSelectionComponent( certInfoType ) )
259  {
260  SELECTION_STATE savedState;
261 
262  /* Determine whether the given component is present or not. This
263  has a somewhat odd status return since it returns the found/
264  notfound status in the return code as well as the returned value,
265  which mirrors the behaviour when reading extension-present
266  pseudo-attributes */
267  saveSelectionState( savedState, certInfoPtr );
268  status = selectGeneralName( certInfoPtr, certInfoType,
269  MAY_BE_ABSENT );
270  if( cryptStatusOK( status ) )
271  status = selectGeneralName( certInfoPtr, CRYPT_ATTRIBUTE_NONE,
272  MUST_BE_PRESENT );
273  restoreSelectionState( savedState, certInfoPtr );
274  *certInfo = cryptStatusOK( status ) ? TRUE : FALSE;
275 
276  return( status );
277  }
278 
279  /* If it's standard certificate or CMS attribute, return it */
280  if( ( certInfoType >= CRYPT_CERTINFO_FIRST_EXTENSION && \
281  certInfoType <= CRYPT_CERTINFO_LAST_EXTENSION ) || \
282  ( certInfoType >= CRYPT_CERTINFO_FIRST_CMS && \
283  certInfoType <= CRYPT_CERTINFO_LAST_CMS ) )
284  {
285  return( getCertAttributeComponent( certInfoPtr, certInfoType,
286  certInfo ) );
287  }
288 
289  /* If it's anything else, handle it specially */
290  switch( certInfoType )
291  {
293  *certInfo = ( certInfoPtr->flags & CERT_FLAG_SELFSIGNED ) ? \
294  TRUE : FALSE;
295  return( CRYPT_OK );
296 
298  *certInfo = ( certInfoPtr->certificate != NULL ) ? TRUE: FALSE;
299  return( CRYPT_OK );
300 
302  {
304 
305  /* Check for the presence of the XYZZY policy OID */
306  attributePtr = findAttributeField( certInfoPtr->attributes,
309  if( attributePtr != NULL )
310  {
311  void *policyOidPtr;
312  int policyOidLength;
313 
314  status = getAttributeDataPtr( attributePtr, &policyOidPtr,
315  &policyOidLength );
316  if( cryptStatusOK( status ) && \
317  policyOidLength == sizeofOID( OID_CRYPTLIB_XYZZYCERT ) && \
318  !memcmp( policyOidPtr, OID_CRYPTLIB_XYZZYCERT,
320  {
321  *certInfo = TRUE;
322  return( CRYPT_OK );
323  }
324  }
325 
326  /* It's not a XYZZY certificate */
327  *certInfo = FALSE;
328  return( CRYPT_OK );
329  }
330 
332  *certInfo = certInfoPtr->type;
333  return( CRYPT_OK );
334 
339  {
340  CRYPT_ATTRIBUTE_TYPE infoID;
341 
342  /* The subject and issuer DNs are treated as pseudo-attributes
343  for manipulation purposes, so if these are selected
344  (indicated by there being no attribute selected since
345  selecting the pseudo-attribute DNs deselects any actual
346  attributes) we have to provide special-case handling for
347  them */
348  if( certInfoPtr->attributeCursor == NULL )
349  {
350  const SELECTION_INFO *currentSelection = \
351  &certInfoPtr->currentSelection;
352 
353  switch( certInfoType )
354  {
357  /* These selection types don't apply to DNs */
358  break;
359 
361  if( currentSelection->dnPtr == &certInfoPtr->subjectName )
362  {
363  *certInfo = CRYPT_CERTINFO_SUBJECTNAME;
364  return( CRYPT_OK );
365  }
366  if( currentSelection->dnPtr == &certInfoPtr->issuerName )
367  {
368  *certInfo = CRYPT_CERTINFO_ISSUERNAME;
369  return( CRYPT_OK );
370  }
371  break;
372 
374  if( currentSelection->dnComponent != CRYPT_ATTRIBUTE_NONE )
375  {
376  *certInfo = currentSelection->dnComponent;
377  return( CRYPT_OK );
378  }
379  break;
380 
381  default:
382  retIntError();
383  }
384  return( CRYPT_ERROR_NOTINITED );
385  }
386 
387  /* The current component and field are usually the same thing
388  since a component is one of a set of entries in a multivalued
389  field, however in the case of complex subtypes (attribute ->
390  generalName -> generalName field) they can be distinct
391  values. To handle this we try for a field ID and if
392  that's not available return the component ID */
393  switch( certInfoType )
394  {
396  status = getAttributeIdInfo( certInfoPtr->attributeCursor,
397  &infoID, NULL, NULL );
398  break;
399 
402  status = getAttributeIdInfo( certInfoPtr->attributeCursor,
403  NULL, &infoID, NULL );
404  break;
405 
407  status = getAttributeIdInfo( certInfoPtr->attributeCursor,
408  NULL, NULL, &infoID );
409  if( cryptStatusError( status ) )
410  status = getAttributeIdInfo( certInfoPtr->attributeCursor,
411  NULL, &infoID, NULL );
412  break;
413 
414  default:
415  retIntError();
416  }
417  if( cryptStatusOK( status ) )
418  *certInfo = infoID;
419  return( status );
420  }
421 
423  if( certInfoPtr->cCertCert->trustedUsage == CRYPT_ERROR )
424  return( CRYPT_ERROR_NOTFOUND );
425  *certInfo = certInfoPtr->cCertCert->trustedUsage;
426  return( CRYPT_OK );
427 
429  status = krnlSendMessage( certInfoPtr->ownerHandle,
431  &certInfoPtr->objectHandle,
433  *certInfo = cryptStatusOK( status ) ? TRUE : FALSE;
434  return( CRYPT_OK );
435 
436 #ifdef USE_CERTREV
438  *certInfo = certInfoPtr->cCertRev->signatureLevel;
439  return( CRYPT_OK );
440 #endif /* USE_CERTREV */
441 
443  *certInfo = certInfoPtr->version;
444  return( CRYPT_OK );
445 
448  {
449  const DN_PTR *dnPtr = \
450  ( certInfoType == CRYPT_CERTINFO_ISSUERNAME ) ? \
451  certInfoPtr->issuerName : certInfoPtr->subjectName;
452 
453  if( dnPtr == NULL )
454  {
455  *certInfo = FALSE;
456  return( CRYPT_ERROR_NOTFOUND );
457  }
458  *certInfo = TRUE;
459  return( CRYPT_OK );
460  }
461 
462 #ifdef USE_CERTVAL
464  {
465  const CERT_VAL_INFO *certValInfo = certInfoPtr->cCertVal;
466  const VALIDITY_INFO *valInfoPtr = \
467  ( certValInfo->currentValidity != NULL ) ? \
468  certValInfo->currentValidity : certValInfo->validityInfo;
469 
470  if( valInfoPtr == NULL )
471  return( CRYPT_ERROR_NOTFOUND );
472  *certInfo = valInfoPtr->extStatus;
473  return( CRYPT_OK );
474  }
475 #endif /* USE_CERTVAL */
476 
477 #ifdef USE_CERTREV
479  {
480  const CERT_REV_INFO *certRevInfo = certInfoPtr->cCertRev;
481  const REVOCATION_INFO *revInfoPtr = \
482  ( certRevInfo->currentRevocation != NULL ) ? \
483  certRevInfo->currentRevocation : certRevInfo->revocations;
484 
485  if( revInfoPtr == NULL )
486  return( CRYPT_ERROR_NOTFOUND );
487  *certInfo = revInfoPtr->status;
488  return( CRYPT_OK );
489  }
490 #endif /* USE_CERTREV */
491 
492  case CRYPT_IATTRIBUTE_CERTKEYALGO:
493  *certInfo = certInfoPtr->publicKeyAlgo;
494  return( CRYPT_OK );
495 
496  case CRYPT_IATTRIBUTE_CERTHASHALGO:
497  *certInfo = certInfoPtr->cCertCert->hashAlgo;
498  return( CRYPT_OK );
499 
500  case CRYPT_IATTRIBUTE_CERTCOPY:
501  {
502  CRYPT_CERTIFICATE certCopy;
503 
504  status = getCertCopy( certInfoPtr, &certCopy, FALSE );
505  if( cryptStatusError( status ) )
506  return( status );
507  *certInfo = certCopy;
508  return( CRYPT_OK );
509  }
510  case CRYPT_IATTRIBUTE_CERTCOPY_DATAONLY:
511  {
512  CRYPT_CERTIFICATE certCopy;
513 
514  status = getCertCopy( certInfoPtr, &certCopy, TRUE );
515  if( cryptStatusError( status ) )
516  return( status );
517  *certInfo = certCopy;
518  return( CRYPT_OK );
519  }
520  }
521 
522  retIntError();
523  }
524 #endif /* USE_CERTIFICATES */