cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
comp_gets.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Get Certificate String Components *
4 * Copyright Peter Gutmann 1997-2009 *
5 * *
6 ****************************************************************************/
7 
8 #include <stdio.h> /* For sprintf() */
9 #if defined( INC_ALL )
10  #include "cert.h"
11  #include "asn1.h"
12  #include "asn1_ext.h"
13 #else
14  #include "cert/cert.h"
15  #include "enc_dec/asn1.h"
16  #include "enc_dec/asn1_ext.h"
17 #endif /* Compiler-specific includes */
18 
19 #ifdef USE_CERTIFICATES
20 
21 /****************************************************************************
22 * *
23 * Utility Routines *
24 * *
25 ****************************************************************************/
26 
27 /* The maximum magnitude of an individual OID arc. Anything larger than
28  this is most likely an error (or something from Microsoft) */
29 
30 #define OID_ARC_MAX 0x1000000L /* 2 ^ 28 */
31 
32 /* The minimum size for an OBJECT IDENTIFIER expressed as ASCII characters */
33 
34 #define MIN_ASCII_OIDSIZE 7
35 
36 /* Convert a binary OID to its text form */
37 
38 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
39 static int oidToText( IN_BUFFER( binaryOidLen ) const BYTE *binaryOID,
40  IN_LENGTH_OID const int binaryOidLen,
41  OUT_BUFFER( maxOidLen, *oidLen ) char *oid,
42  IN_LENGTH_SHORT_MIN( 16 ) const int maxOidLen,
43  OUT_LENGTH_SHORT_Z int *oidLen )
44  {
45  long value = 0;
46  int i, length = 0, subLen;
47 
48  assert( isReadPtr( binaryOID, binaryOidLen ) );
49  assert( isWritePtr( oid, maxOidLen ) );
50  assert( isWritePtr( oidLen, sizeof( int ) ) );
51 
52  REQUIRES( binaryOidLen >= MIN_OID_SIZE && \
53  binaryOidLen <= MAX_OID_SIZE && \
54  binaryOidLen == sizeofOID( binaryOID ) );
55  REQUIRES( maxOidLen >= 16 && maxOidLen < MAX_INTLENGTH_SHORT );
56 
57  /* Clear return values */
58  memset( oid, 0, min( 16, maxOidLen ) );
59  *oidLen = 0;
60 
61  for( i = 2; i < binaryOidLen; i++ )
62  {
63  const BYTE data = binaryOID[ i ];
64  const long valTmp = value << 7;
65 
66  /* Pick apart the encoding */
67  if( value == 0 && data == 0x80 )
68  {
69  /* Invalid leading zero value, ( 0x80 & 0x7F ) == 0 */
70  return( CRYPT_ERROR_BADDATA );
71  }
72  if( value >= ( OID_ARC_MAX >> 7 ) || \
73  valTmp >= OID_ARC_MAX - ( data & 0x7F ) )
74  return( CRYPT_ERROR_BADDATA ); /* Overflow */
75  value = valTmp | ( data & 0x7F );
76  if( value < 0 || value > OID_ARC_MAX )
77  return( CRYPT_ERROR_BADDATA ); /* Range error */
78  if( !( data & 0x80 ) )
79  {
80  /* Make sure that we don't overflow the buffer. The value 20 is
81  the maximum magnitude of a 64-bit int plus space plus 1-byte
82  overflow */
83  if( length >= maxOidLen - 20 )
84  return( CRYPT_ERROR_BADDATA );
85 
86  if( length == 0 )
87  {
88  long x, y;
89 
90  /* The first two levels are encoded into one byte since the
91  root level has only 3 nodes (40*x + y), however if x =
92  joint-iso-itu-t(2) then y may be > 39, so we have to add
93  special-case handling for this */
94  x = value / 40;
95  y = value % 40;
96  if( x > 2 )
97  {
98  /* Handle special case for large y if x == 2 */
99  y += ( x - 2 ) * 40;
100  x = 2;
101  }
102  if( x < 0 || x > 2 || y < 0 || \
103  ( ( x < 2 && y > 39 ) || \
104  ( x == 2 && ( y > 50 && y != 100 ) ) ) )
105  {
106  /* If x = 0 or 1 then y has to be 0...39, for x = 3
107  it can take any value but there are no known
108  assigned values over 50 except for one contrived
109  example in X.690 which sets y = 100, so if we see
110  something outside this range it's most likely an
111  encoding error rather than some bizarre new ID
112  that's just appeared */
113  return( CRYPT_ERROR_BADDATA );
114  }
115  subLen = sprintf_s( oid, maxOidLen, "%ld %ld", x, y );
116  }
117  else
118  {
119  subLen = sprintf_s( oid + length, maxOidLen - length,
120  " %ld", value );
121  }
122  if( subLen < 2 || subLen > maxOidLen - length )
123  return( CRYPT_ERROR_BADDATA );
124  length += subLen;
125  value = 0;
126  }
127 
128  }
129  if( value != 0 )
130  {
131  /* We stopped in the middle of a continued value, it's an invalid
132  encoding */
133  return( CRYPT_ERROR_BADDATA );
134  }
135  *oidLen = length;
136 
137  return( CRYPT_OK );
138  }
139 
140 /* Convert an ASCII OID arc sequence into an encoded OID. We allow dots as
141  well as whitespace for arc separators, these are an IETF-ism but are in
142  common use */
143 
144 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
145 static int scanValue( IN_BUFFER( strMaxLength ) const char *string,
146  IN_LENGTH_ATTRIBUTE const int strMaxLength,
147  OUT_INT_Z long *value )
148  {
149  int intValue, index, status;
150 
151  assert( isReadPtr( string, strMaxLength ) );
152  assert( isWritePtr( value, sizeof( long ) ) );
153 
154  REQUIRES( strMaxLength > 0 && strMaxLength <= CRYPT_MAX_TEXTSIZE );
155 
156  /* Clear return value */
157  *value = 0;
158 
159  /* Look for the end of the arc */
160  for( index = 0; index < strMaxLength; index++ )
161  {
162  if( string[ index ] == ' ' || string[ index ] == '.' )
163  break;
164  }
165  if( index <= 0 || index > CRYPT_MAX_TEXTSIZE )
166  return( -1 );
167  status = strGetNumeric( string, index, &intValue, 0, OID_ARC_MAX );
168  if( cryptStatusError( status ) )
169  return( -1 );
170  *value = intValue;
171  if( index < strMaxLength && \
172  ( string[ index ] == ' ' || string[ index ] == '.' ) )
173  {
174  /* There's more to go, skip the delimiter */
175  index++;
176  }
177  return( index );
178  }
179 
180 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
181 int textToOID( IN_BUFFER( textOidLength ) const char *textOID,
182  IN_RANGE( MIN_ASCII_OIDSIZE, CRYPT_MAX_TEXTSIZE ) \
183  const int textOidLength,
184  OUT_BUFFER( binaryOidMaxLen, *binaryOidLen ) BYTE *binaryOID,
185  IN_LENGTH_SHORT const int binaryOidMaxLen,
186  OUT_LENGTH_SHORT_Z int *binaryOidLen )
187  {
188  const char *textOidPtr;
189  long value, value2;
190  int length = 3, subLen, dataLeft, iterationCount, status;
191 
192  assert( isReadPtr( textOID, textOidLength ) );
193  assert( isWritePtr( binaryOID, binaryOidMaxLen ) );
194  assert( isWritePtr( binaryOidLen, sizeof( int ) ) );
195 
196  REQUIRES( textOidLength >= MIN_ASCII_OIDSIZE && \
197  textOidLength <= CRYPT_MAX_TEXTSIZE );
198  REQUIRES( binaryOidMaxLen >= 5 && \
199  binaryOidMaxLen < MAX_INTLENGTH_SHORT );
200 
201  /* Clear return value */
202  memset( binaryOID, 0, min( 16, binaryOidMaxLen ) );
203  *binaryOidLen = 0;
204 
205  /* Perform some basic checks on the OID data */
206  status = dataLeft = strStripWhitespace( &textOidPtr, textOID,
207  textOidLength );
208  if( cryptStatusError( status ) )
209  return( CRYPT_ERROR_BADDATA );
210 
211  /* Make sure that the first two arcs are in order */
212  subLen = scanValue( textOidPtr, dataLeft, &value );
213  if( subLen <= 0 || subLen > CRYPT_MAX_TEXTSIZE )
214  return( CRYPT_ERROR_BADDATA );
215  textOidPtr += subLen;
216  dataLeft -= subLen;
217  if( dataLeft <= 0 || dataLeft > CRYPT_MAX_TEXTSIZE )
218  return( CRYPT_ERROR_BADDATA );
219  subLen = scanValue( textOidPtr, dataLeft, &value2 );
220  if( subLen <= 0 || subLen > CRYPT_MAX_TEXTSIZE )
221  return( CRYPT_ERROR_BADDATA );
222  textOidPtr += subLen;
223  dataLeft -= subLen;
224  if( dataLeft <= 0 || dataLeft > CRYPT_MAX_TEXTSIZE )
225  return( CRYPT_ERROR_BADDATA );
226  if( value < 0 || value > 2 || value2 < 1 || \
227  ( ( value < 2 && value2 > 39 ) || ( value == 2 && value2 > 175 ) ) )
228  return( CRYPT_ERROR_BADDATA );
229  binaryOID[ 0 ] = 0x06; /* OBJECT IDENTIFIER tag */
230  binaryOID[ 2 ] = ( BYTE )( ( value * 40 ) + value2 );
231 
232  /* Convert the remaining arcs */
233  for( iterationCount = 0;
234  dataLeft > 0 && iterationCount < FAILSAFE_ITERATIONS_MED;
235  iterationCount++ )
236  {
237  BOOLEAN hasHighBits = FALSE;
238 
239  /* Scan the next value and write the high octets (if necessary) with
240  flag bits set, followed by the final octet */
241  subLen = scanValue( textOidPtr, dataLeft, &value );
242  if( subLen <= 0 || subLen > CRYPT_MAX_TEXTSIZE )
243  return( CRYPT_ERROR_BADDATA );
244  textOidPtr += subLen;
245  dataLeft -= subLen;
246  if( dataLeft < 0 || dataLeft > CRYPT_MAX_TEXTSIZE )
247  return( CRYPT_ERROR_BADDATA );
248  if( value >= 0x200000L ) /* 2^21 */
249  {
250  if( length >= binaryOidMaxLen )
251  return( CRYPT_ERROR_BADDATA );
252  binaryOID[ length++ ] = intToByte( 0x80 | ( value >> 21 ) );
253  value %= 0x200000L;
254  hasHighBits = TRUE;
255  }
256  if( ( value >= 0x4000 ) || hasHighBits ) /* 2^14 */
257  {
258  if( length >= binaryOidMaxLen )
259  return( CRYPT_ERROR_BADDATA );
260  binaryOID[ length++ ] = intToByte( 0x80 | ( value >> 14 ) );
261  value %= 0x4000;
262  hasHighBits = TRUE;
263  }
264  if( ( value >= 0x80 ) || hasHighBits ) /* 2^7 */
265  {
266  if( length >= binaryOidMaxLen )
267  return( CRYPT_ERROR_BADDATA );
268  binaryOID[ length++ ] = intToByte( 0x80 | ( value >> 7 ) );
269  value %= 128;
270  }
271  if( length >= binaryOidMaxLen )
272  return( CRYPT_ERROR_BADDATA );
273  binaryOID[ length++ ] = intToByte( value );
274  }
275  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
276  binaryOID[ 1 ] = intToByte( length - 2 );
277  *binaryOidLen = length;
278 
279  return( CRYPT_OK );
280  }
281 
282 /****************************************************************************
283 * *
284 * Get Certificate Components *
285 * *
286 ****************************************************************************/
287 
288 /* Get a certificate component */
289 
290 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 5 ) ) \
291 static int getCertAttributeComponent( const CERT_INFO *certInfoPtr,
294  void *certInfo,
297  {
299  void *dataPtr;
300  int dataLength, status;
301 
302  assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
303  assert( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
304  ( isWritePtr( certInfo, certInfoMaxLength ) ) );
305  assert( isWritePtr( certInfoLength, sizeof( int ) ) );
306 
307  REQUIRES( certInfoType > CRYPT_ATTRIBUTE_NONE && \
308  certInfoType < CRYPT_ATTRIBUTE_LAST );
309  REQUIRES( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
310  ( certInfo != NULL && \
311  certInfoMaxLength > 0 && \
312  certInfoMaxLength < MAX_INTLENGTH_SHORT ) );
313 
314  /* Clear return values */
315  if( certInfo != NULL )
316  memset( certInfo, 0, min( 16, certInfoMaxLength ) );
317  *certInfoLength = 0;
318 
319  /* Try and find this attribute in the attribute list */
320  attributePtr = findAttributeComponent( certInfoPtr, certInfoType );
321  if( attributePtr == NULL )
322  return( CRYPT_ERROR_NOTFOUND );
323 
324  /* String fields never have default values (only BOOLEANs do) and never
325  denote complete-attribute entries (these are indicated by a present/
326  not-present BOOLEAN) */
327  ENSURES( !checkAttributeProperty( attributePtr,
329  ENSURES( !checkAttributeProperty( attributePtr,
331 
332  /* If the data type is an OID we have to convert it to a human-readable
333  form before we return it */
334  if( checkAttributeProperty( attributePtr, ATTRIBUTE_PROPERTY_OID ) )
335  {
336  char textOID[ ( CRYPT_MAX_TEXTSIZE * 2 ) + 8 ];
337  int textOidLength;
338 
339  status = getAttributeDataPtr( attributePtr, &dataPtr, &dataLength );
340  if( cryptStatusError( status ) )
341  return( status );
342  status = oidToText( dataPtr, dataLength, textOID,
343  CRYPT_MAX_TEXTSIZE * 2, &textOidLength );
344  if( cryptStatusError( status ) )
345  return( status );
346  *certInfoLength = textOidLength;
347  if( certInfo == NULL )
348  return( CRYPT_OK );
349  return( attributeCopyParams( certInfo, certInfoMaxLength,
350  certInfoLength, textOID,
351  textOidLength ) );
352  }
353 
354  /* Get the attribute component data */
355  status = getAttributeDataPtr( attributePtr, &dataPtr, &dataLength );
356  if( cryptStatusError( status ) )
357  return( status );
358  return( attributeCopyParams( certInfo, certInfoMaxLength,
359  certInfoLength, dataPtr, dataLength ) );
360  }
361 
362 /* Get the hash of a certificate */
363 
364 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 5 ) ) \
365 static int getCertHash( INOUT CERT_INFO *certInfoPtr,
366  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE certInfoType,
367  OUT_BUFFER_OPT( certInfoMaxLength, \
368  *certInfoLength ) void *certInfo,
369  IN_LENGTH_SHORT_Z const int certInfoMaxLength,
370  OUT_LENGTH_SHORT_Z int *certInfoLength )
371  {
372  static const MAP_TABLE hashAlgoMapTbl[] = {
377  { CRYPT_ERROR, 0 }, { CRYPT_ERROR, 0 }
378  };
379  HASHFUNCTION_ATOMIC hashFunctionAtomic;
380  BYTE hash[ CRYPT_MAX_HASHSIZE + 8 ];
381  int hashAlgo, hashSize, status;
382 
383  assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
384  assert( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
385  ( isWritePtr( certInfo, certInfoMaxLength ) ) );
386  assert( isWritePtr( certInfoLength, sizeof( int ) ) );
387 
388  REQUIRES( certInfoType == CRYPT_CERTINFO_FINGERPRINT_MD5 || \
389  certInfoType == CRYPT_CERTINFO_FINGERPRINT_SHA1 || \
390  certInfoType == CRYPT_CERTINFO_FINGERPRINT_SHA2 || \
391  certInfoType == CRYPT_CERTINFO_FINGERPRINT_SHAng );
392  REQUIRES( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
393  ( certInfo != NULL && \
394  certInfoMaxLength > 0 && \
395  certInfoMaxLength < MAX_INTLENGTH_SHORT ) );
396 
397  /* Clear return values */
398  if( certInfo != NULL )
399  memset( certInfo, 0, min( 16, certInfoMaxLength ) );
400  *certInfoLength = 0;
401 
402  /* Get the hash algorithm information */
403  status = mapValue( certInfoType, &hashAlgo, hashAlgoMapTbl,
404  FAILSAFE_ARRAYSIZE( hashAlgoMapTbl, MAP_TABLE ) );
405  ENSURES( cryptStatusOK( status ) );
406  getHashAtomicParameters( hashAlgo, 0, &hashFunctionAtomic, &hashSize );
407  *certInfoLength = hashSize;
408  if( certInfo == NULL )
409  return( CRYPT_OK );
410  ENSURES( certInfoPtr->certificate != NULL );
411 
412  /* Write the hash (fingerprint) to the output */
413  if( hashAlgo == CRYPT_ALGO_SHA1 && certInfoPtr->certHashSet )
414  {
415  /* If we've got a cached certificate hash present, return that instead of
416  re-hashing the certificate */
417  return( attributeCopyParams( certInfo, certInfoMaxLength,
418  certInfoLength, certInfoPtr->certHash,
419  KEYID_SIZE ) );
420  }
421  hashFunctionAtomic( hash, CRYPT_MAX_HASHSIZE, certInfoPtr->certificate,
422  certInfoPtr->certificateSize );
423  if( hashAlgo == CRYPT_ALGO_SHA1 )
424  {
425  /* Remember the hash/fingerprint/oobCertID/certHash/thumbprint/
426  whatever for later since this is reused frequently */
427  memcpy( certInfoPtr->certHash, hash, hashSize );
428  certInfoPtr->certHashSet = TRUE;
429  }
430  return( attributeCopyParams( certInfo, certInfoMaxLength,
431  certInfoLength, hash, hashSize ) );
432  }
433 
434 /* Get the ESSCertID for a certificate */
435 
436 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
437 static int getESSCertID( INOUT CERT_INFO *certInfoPtr,
438  OUT_BUFFER_OPT( certInfoMaxLength, \
439  *certInfoLength ) void *certInfo,
440  IN_LENGTH_SHORT_Z const int certInfoMaxLength,
441  OUT_LENGTH_SHORT_Z int *certInfoLength )
442  {
443  STREAM stream;
444  BYTE certHash[ CRYPT_MAX_HASHSIZE + 8 ];
445  int certHashSize, issuerSerialDataSize, status;
446 
447  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
448  assert( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
449  ( isWritePtr( certInfo, certInfoMaxLength ) ) );
450  assert( isWritePtr( certInfoLength, sizeof( int ) ) );
451 
452  REQUIRES( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
453  ( certInfo != NULL && \
454  certInfoMaxLength > 0 && \
455  certInfoMaxLength < MAX_INTLENGTH_SHORT ) );
456 
457  /* Clear return values */
458  if( certInfo != NULL )
459  memset( certInfo, 0, min( 16, certInfoMaxLength ) );
460  *certInfoLength = 0;
461 
462  /* Get the certificate ID */
463  status = getCertHash( certInfoPtr, CRYPT_CERTINFO_FINGERPRINT_SHA1,
464  certHash, CRYPT_MAX_HASHSIZE, &certHashSize );
465  if( cryptStatusError( status ) )
466  return( status );
467  REQUIRES( certInfoPtr->cCertCert->serialNumber != NULL );
468 
469  /* Write the ESSCertID:
470 
471  ESSCertID ::= SEQUENCE {
472  certHash OCTET STRING SIZE(20),
473  issuerSerial SEQUENCE {
474  issuer SEQUENCE { [4] EXPLICIT Name },
475  serial INTEGER
476  }
477  } */
478  issuerSerialDataSize = ( int ) \
479  sizeofObject( sizeofObject( certInfoPtr->issuerDNsize ) ) + \
480  sizeofInteger( certInfoPtr->cCertCert->serialNumber,
481  certInfoPtr->cCertCert->serialNumberLength );
482  *certInfoLength = ( int ) \
483  sizeofObject( sizeofObject( certHashSize ) + \
484  sizeofObject( issuerSerialDataSize ) );
485  if( certInfo == NULL )
486  return( CRYPT_OK );
487  if( *certInfoLength > certInfoMaxLength )
488  return( CRYPT_ERROR_OVERFLOW );
489  sMemOpen( &stream, certInfo, *certInfoLength );
490  writeSequence( &stream, sizeofObject( certHashSize ) + \
491  sizeofObject( issuerSerialDataSize ) );
492  writeOctetString( &stream, certHash, certHashSize, DEFAULT_TAG );
493  writeSequence( &stream, issuerSerialDataSize );
494  writeSequence( &stream, sizeofObject( certInfoPtr->issuerDNsize ) );
495  writeConstructed( &stream, certInfoPtr->issuerDNsize, 4 );
496  swrite( &stream, certInfoPtr->issuerDNptr, certInfoPtr->issuerDNsize );
497  status = writeInteger( &stream, certInfoPtr->cCertCert->serialNumber,
498  certInfoPtr->cCertCert->serialNumberLength,
499  DEFAULT_TAG );
500  sMemDisconnect( &stream );
501  ENSURES( cryptStatusOK( status ) );
502 
503  return( status );
504  }
505 
506 /****************************************************************************
507 * *
508 * Get Validity Components *
509 * *
510 ****************************************************************************/
511 
512 #ifdef USE_CERTVAL
513 
514 /* Get a pointer to the currently selected validity time */
515 
517 time_t *getValidityTimePtr( const CERT_INFO *certInfoPtr )
518  {
519  CERT_VAL_INFO *certValInfo = certInfoPtr->cCertVal;
520 
521  assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
522 
523  REQUIRES_N( certInfoPtr->type == CRYPT_CERTTYPE_RTCS_RESPONSE );
524 
525  /* If there's a specific validity entry selected get its invalidity time,
526  otherwise if there are invalid certificates present get the first
527  certificate's invalidity time, otherwise get the default invalidity
528  time */
529  return( ( certValInfo->currentValidity != NULL ) ? \
530  &certValInfo->currentValidity->invalidityTime : \
531  ( certValInfo->validityInfo != NULL ) ? \
532  &certValInfo->validityInfo->invalidityTime : NULL );
533  }
534 #endif /* USE_CERTVAL */
535 
536 /****************************************************************************
537 * *
538 * Get Revocation Components *
539 * *
540 ****************************************************************************/
541 
542 #ifdef USE_CERTREV
543 
544 /* Encode a single CRL entry into the external format, used when storing a
545  CRL to a certificate store */
546 
547 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
548 static int getCrlEntry( INOUT CERT_INFO *certInfoPtr,
549  OUT_BUFFER_OPT( certInfoMaxLength, \
550  *certInfoLength ) void *certInfo,
551  IN_LENGTH_SHORT_Z const int certInfoMaxLength,
552  OUT_LENGTH_SHORT_Z int *certInfoLength )
553  {
554  CERT_REV_INFO *certRevInfo = certInfoPtr->cCertRev;
555  STREAM stream;
556  WRITECERT_FUNCTION writeCertFunction;
557  int crlEntrySize = DUMMY_INIT, status;
558 
559  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
560  assert( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
561  ( isWritePtr( certInfo, certInfoMaxLength ) ) );
562  assert( isWritePtr( certInfoLength, sizeof( int ) ) );
563 
564  REQUIRES( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
565  ( certInfo != NULL && \
566  certInfoMaxLength > 0 && \
567  certInfoMaxLength < MAX_INTLENGTH_SHORT ) );
568  REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CRL );
569 
570  /* Clear return values */
571  if( certInfo != NULL )
572  memset( certInfo, 0, min( 16, certInfoMaxLength ) );
573  *certInfoLength = 0;
574 
575  if( certRevInfo->currentRevocation == NULL )
576  return( CRYPT_ERROR_NOTFOUND );
577 
578  /* Determine how big the encoded CRL entry will be. Doing it directly
579  in this manner is somewhat ugly but the only other way to do it would
580  be to pseudo-sign the certificate object in order to write the data,
581  which doesn't work for CRL entries where we could end up pseudo-
582  signing it multiple times */
583  writeCertFunction = getCertWriteFunction( CRYPT_CERTTYPE_CRL );
584  ENSURES( writeCertFunction != NULL );
585  sMemNullOpen( &stream );
586  status = writeCertFunction( &stream, certInfoPtr, NULL, CRYPT_UNUSED );
587  if( cryptStatusOK( status ) )
588  crlEntrySize = stell( &stream );
589  sMemClose( &stream );
590  if( cryptStatusError( status ) )
591  return( status );
592 
593  /* Write the encoded single CRL entry */
594  *certInfoLength = crlEntrySize;
595  if( certInfo == NULL )
596  return( CRYPT_OK );
597  if( crlEntrySize > certInfoMaxLength )
598  return( CRYPT_ERROR_OVERFLOW );
599  sMemOpen( &stream, certInfo, crlEntrySize );
600  status = writeCertFunction( &stream, certInfoPtr, NULL, CRYPT_UNUSED );
601  sMemDisconnect( &stream );
602 
603  return( status );
604  }
605 
606 /* Get a pointer to the currently selected revocation time */
607 
609 time_t *getRevocationTimePtr( const CERT_INFO *certInfoPtr )
610  {
611  CERT_REV_INFO *certRevInfo = certInfoPtr->cCertRev;
612 
613  assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
614 
615  REQUIRES_N( certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
616  certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST || \
617  certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE );
618 
619  /* If there's a specific revocation entry selected, get its revocation
620  time, otherwise if there are revoked certificates present get the
621  first certificate's revocation time, otherwise get the default
622  revocation time */
623  return( ( certRevInfo->currentRevocation != NULL ) ? \
624  &certRevInfo->currentRevocation->revocationTime : \
625  ( certRevInfo->revocations != NULL ) ? \
626  &certRevInfo->revocations->revocationTime : \
627  ( certRevInfo->revocationTime ) ? \
628  &certRevInfo->revocationTime : NULL );
629  }
630 #endif /* USE_CERTREV */
631 
632 /****************************************************************************
633 * *
634 * Get Certificate Owner Components *
635 * *
636 ****************************************************************************/
637 
638 /* Get the issuerAndSerialNumber for a certificate */
639 
640 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
641 static int getIAndS( const CERT_INFO *certInfoPtr,
642  OUT_BUFFER_OPT( certInfoMaxLength, \
643  *certInfoLength ) void *certInfo,
644  IN_LENGTH_SHORT_Z const int certInfoMaxLength,
645  OUT_LENGTH_SHORT_Z int *certInfoLength )
646  {
647  STREAM stream;
648  void *serialNumber;
650 
651  assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
652  assert( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
653  ( isWritePtr( certInfo, certInfoMaxLength ) ) );
654  assert( isWritePtr( certInfoLength, sizeof( int ) ) );
655 
656  REQUIRES( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
657  ( certInfo != NULL && \
658  certInfoMaxLength > 0 && \
659  certInfoMaxLength < MAX_INTLENGTH_SHORT ) );
660 
661  /* Clear return values */
662  if( certInfo != NULL )
663  memset( certInfo, 0, min( 16, certInfoMaxLength ) );
664  *certInfoLength = 0;
665 
666 #ifdef USE_CERTREV
667  /* If it's a CRL, use the serial number of the currently selected CRL
668  entry */
669  if( certInfoPtr->type == CRYPT_CERTTYPE_CRL )
670  {
671  REVOCATION_INFO *crlInfoPtr = certInfoPtr->cCertRev->currentRevocation;
672 
673  REQUIRES( crlInfoPtr != NULL );
674 
675  serialNumber = crlInfoPtr->id;
676  serialNumberLength = crlInfoPtr->idLength;
677  }
678  else
679 #endif /* USE_CERTREV */
680  {
681  serialNumber = certInfoPtr->cCertCert->serialNumber;
682  serialNumberLength = certInfoPtr->cCertCert->serialNumberLength;
683  }
684  ENSURES( serialNumber != NULL );
685  *certInfoLength = ( int ) \
686  sizeofObject( certInfoPtr->issuerDNsize + \
687  sizeofInteger( serialNumber, \
688  serialNumberLength ) );
689  if( certInfo == NULL )
690  return( CRYPT_OK );
691  if( *certInfoLength > certInfoMaxLength )
692  return( CRYPT_ERROR_OVERFLOW );
693  sMemOpen( &stream, certInfo, *certInfoLength );
694  writeSequence( &stream, certInfoPtr->issuerDNsize + \
695  sizeofInteger( serialNumber, serialNumberLength ) );
696  swrite( &stream, certInfoPtr->issuerDNptr, certInfoPtr->issuerDNsize );
697  status = writeInteger( &stream, serialNumber, serialNumberLength,
698  DEFAULT_TAG );
699  sMemDisconnect( &stream );
700 
701  return( status );
702  }
703 
704 /* Look for a named DN component (e.g. "surname = Smith") in an RFC 1779-
705  encoded DN. We have to use the text-string encoded form because we're
706  looking for arbitrarily odd components not all of which are handled
707  directly by cryptlib */
708 
709 #if 0 /* 18/7/08 Unlikely that we'd ever find a certificate this broken,
710  and it's just a potential attack vector due to the complexity of
711  the processing */
712 
713 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5, 6 ) ) \
714 static int extractDnComponent( IN_BUFFER( encodedDnLength ) \
715  const char *encodedDn,
716  IN_LENGTH_SHORT const int encodedDnLength,
717  IN_BUFFER( componentNameLength ) \
718  const char *componentName,
719  IN_LENGTH_SHORT const int componentNameLength,
721  OUT_LENGTH_SHORT_Z int *length )
722  {
723  int startPos, endPos;
724 
725  assert( isReadPtr( encodedDn, encodedDnLength ) );
726  assert( isReadPtr( componentName, componentNameLength ) );
727  assert( isWritePtr( startOffset, sizeof( int ) ) );
728  assert( isWritePtr( length, sizeof( int ) ) );
729 
730  REQUIRES( encodedDnLength > 0 && \
731  encodedDnLength < MAX_INTLENGTH_SHORT );
732  REQUIRES( componentNameLength > 0 && \
733  componentNameLength < MAX_INTLENGTH_SHORT );
734 
735  /* Clear return values */
736  *startOffset = *length = 0;
737 
738  /* Try and find the component type name in the RFC 1779-encoded DN
739  string. This scans the DN string for a matching type in a
740  type-and-value pair, e.g. "surname = Smith" */
741  startPos = strFindStr( encodedDn, encodedDnLength,
742  componentName, componentNameLength );
743  if( startPos < 0 )
744  return( -1 );
745  startPos += componentNameLength; /* Skip type indicator */
746 
747  /* Extract the component value */
748  for( endPos = startPos; endPos < encodedDnLength && \
749  encodedDn[ endPos ] != ',' && \
750  encodedDn[ endPos ] != '+'; endPos++ );
751  if( endPos > startPos && \
752  encodedDn[ endPos ] == '+' && \
753  encodedDn[ endPos - 1 ] == ' ' )
754  endPos--; /* Strip trailing space */
755  if( endPos <= startPos )
756  return( -1 );
757 
758  *startOffset = startPos;
759  *length = endPos - startPos;
760 
761  return( CRYPT_OK );
762  }
763 
764 /* Assemble name components from an RFC 1779-encoded DN string. We have to
765  use the text-string encoded form because we're looking for arbitrarily
766  odd components not all of which are handled directly by cryptlib */
767 
768 CHECK_RETVAL STDC_NONNULL_ARG( ( 3, 4 ) ) \
769 static int getNameFromDN( OUT_BUFFER_OPT( nameMaxLength, *nameLength ) void *name,
770  IN_LENGTH_SHORT_Z const int nameMaxLength,
771  OUT_LENGTH_SHORT_Z int *nameLength,
772  IN_BUFFER( encodedDnLength ) const char *encodedDn,
773  IN_LENGTH_SHORT const int encodedDnLength )
774  {
775  int startPos, length, status;
776 
777  assert( ( name == NULL && nameMaxLength == 0 ) || \
778  ( isWritePtr( name, nameMaxLength ) ) );
779  assert( isWritePtr( nameLength, sizeof( int ) ) );
780  assert( isReadPtr( encodedDn, encodedDnLength ) );
781 
782  REQUIRES( ( name == NULL && nameMaxLength == 0 ) || \
783  ( name != NULL && \
784  nameMaxLength > 0 && \
785  nameMaxLength < MAX_INTLENGTH_SHORT ) );
786  REQUIRES( encodedDnLength > 0 && \
787  encodedDnLength < MAX_INTLENGTH_SHORT );
788 
789  /* Clear return values */
790  if( name != NULL )
791  memset( name, 0, min( 16, nameMaxLength ) );
792  *nameLength = 0;
793 
794  /* Look for a pseudonym */
795  status = extractDnComponent( encodedDn, encodedDnLength,
796  "oid.2.5.4.65=", 13, &startPos, &length );
797  if( cryptStatusOK( status ) && \
798  length > 0 && length <= nameMaxLength )
799  {
800  return( attributeCopyParams( name, nameMaxLength, nameLength,
801  encodedDn + startPos, length ) );
802  }
803 
804  /* Look for givenName + surname */
805  status = extractDnComponent( encodedDn, encodedDnLength,
806  "G=", 2, &startPos, &length );
807  if( cryptStatusOK( status ) && \
808  length > 0 && length <= nameMaxLength )
809  {
810  char nameBuffer[ MAX_ATTRIBUTE_SIZE + 8 ];
811  int startPos2, length2;
812 
813  status = extractDnComponent( encodedDn, encodedDnLength,
814  "S=", 2, &startPos2, &length2 );
815  if( cryptStatusOK( status ) && \
816  length2 > 0 && length + length2 <= nameMaxLength && \
817  length + length2 < MAX_ATTRIBUTE_SIZE )
818  {
819  memcpy( nameBuffer, encodedDn + startPos, length );
820  memcpy( nameBuffer + length, encodedDn + startPos2, length2 );
821  return( attributeCopyParams( name, nameMaxLength, nameLength,
822  nameBuffer, length + length2 ) );
823  }
824  }
825 
826  /* We couldn't find anything useful */
827  return( CRYPT_ERROR_NOTFOUND );
828  }
829 #endif /* 0 */
830 
831 /* Get the certificate holder's name, usually the commonName but if that's
832  not present then some commonName-equivalent */
833 
834 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
835 static int getHolderName( const CERT_INFO *certInfoPtr,
836  OUT_BUFFER_OPT( certInfoMaxLength, \
837  *certInfoLength ) void *certInfo,
838  IN_LENGTH_SHORT_Z const int certInfoMaxLength,
839  OUT_LENGTH_SHORT_Z int *certInfoLength )
840  {
841  int status;
842 
843  assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
844  assert( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
845  ( isWritePtr( certInfo, certInfoMaxLength ) ) );
846  assert( isWritePtr( certInfoLength, sizeof( int ) ) );
847 
848  REQUIRES( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
849  ( certInfo != NULL && \
850  certInfoMaxLength > 0 && \
851  certInfoMaxLength < MAX_INTLENGTH_SHORT ) );
852 
853  /* Clear return values */
854  if( certInfo != NULL )
855  memset( certInfo, 0, min( 16, certInfoMaxLength ) );
856  *certInfoLength = 0;
857 
858  /* First we try for a CN */
859  status = getDNComponentValue( certInfoPtr->subjectName,
860  CRYPT_CERTINFO_COMMONNAME, 0, certInfo,
861  certInfoMaxLength, certInfoLength );
862  if( cryptStatusOK( status ) )
863  return( CRYPT_OK );
864 
865 #if 0 /* 18/7/08 Unlikely that we'd ever find a certificate this broken,
866  and it's just a potential attack vector due to the complexity of
867  the processing */
868  /* If that fails we try for either a pseudonym or givenName + surname.
869  Since these are part of the vast collection of oddball DN attributes
870  that aren't handled directly we have to get the encoded DN form and
871  look for them by OID (ugh) */
872  sMemOpen( &stream, encodedDnBuffer, MAX_ATTRIBUTE_SIZE );
873  status = writeDNstring( &stream, certInfoPtr->subjectName );
874  if( cryptStatusOK( status ) )
875  status = getNameFromDN( certInfo, certInfoMaxLength, certInfoLength,
876  encodedDnBuffer, stell( &stream ) );
877  sMemDisconnect( &stream );
878  if( cryptStatusOK( status ) )
879  return( status );
880 #endif /* 0 */
881 
882  /* It's possible (although highly unlikely) that a certificate won't
883  have a usable CN-equivalent in some form, in which case we use the OU
884  instead. If that also fails we use the O. This gets a bit messy,
885  but duplicating the OU / O into the CN seems to be the best way to
886  handle this */
887  status = getDNComponentValue( certInfoPtr->subjectName,
889  certInfo, certInfoMaxLength,
890  certInfoLength );
891  if( cryptStatusError( status ) )
892  status = getDNComponentValue( certInfoPtr->subjectName,
894  certInfo, certInfoMaxLength,
895  certInfoLength );
896  return( status );
897  }
898 
899 /* Get the certificate holder's URI, usually an email address but sometimes
900  also a URL */
901 
902 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
903 static int getHolderURI( const CERT_INFO *certInfoPtr,
904  OUT_BUFFER_OPT( certInfoMaxLength, \
905  *certInfoLength ) void *certInfo,
906  IN_LENGTH_SHORT_Z const int certInfoMaxLength,
907  OUT_LENGTH_SHORT_Z int *certInfoLength )
908  {
910  void *dataPtr;
911  int dataLength, status;
912 
913  assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
914  assert( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
915  ( isWritePtr( certInfo, certInfoMaxLength ) ) );
916  assert( isWritePtr( certInfoLength, sizeof( int ) ) );
917 
918  REQUIRES( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
919  ( certInfo != NULL && \
920  certInfoMaxLength > 0 && \
921  certInfoMaxLength < MAX_INTLENGTH_SHORT ) );
922 
923  /* Clear return values */
924  if( certInfo != NULL )
925  memset( certInfo, 0, min( 16, certInfoMaxLength ) );
926  *certInfoLength = 0;
927 
928  /* Find the subjectAltName, which contains the URI information */
929  attributePtr = findAttribute( certInfoPtr->attributes,
931  if( attributePtr == NULL )
932  return( CRYPT_ERROR_NOTFOUND );
933 
934  /* There's altName data present, try for an email address and if that
935  fails, a URL and an FQDN */
936  attributePtr = findAttributeField( attributePtr,
939  if( attributePtr == NULL )
940  attributePtr = findAttributeField( attributePtr,
943  if( attributePtr == NULL )
944  attributePtr = findAttributeField( attributePtr,
947  if( attributePtr == NULL )
948  return( CRYPT_ERROR_NOTFOUND );
949 
950  /* Get the attribute component data */
951  status = getAttributeDataPtr( attributePtr, &dataPtr, &dataLength );
952  if( cryptStatusError( status ) )
953  return( status );
954  return( attributeCopyParams( certInfo, certInfoMaxLength,
955  certInfoLength, dataPtr, dataLength ) );
956  }
957 
958 /****************************************************************************
959 * *
960 * Get Miscellaneous Certificate Components *
961 * *
962 ****************************************************************************/
963 
964 #ifdef USE_PKIUSER
965 
966 /* Encode PKI user information (IDs and passwords) into the external
967  text-encoded format */
968 
969 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 5 ) ) \
970 static int getPkiUserInfo( const CERT_INFO *certInfoPtr,
971  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE certInfoType,
972  OUT_BUFFER_OPT( certInfoMaxLength, \
973  *certInfoLength ) void *certInfo,
974  IN_LENGTH_SHORT_Z const int certInfoMaxLength,
975  OUT_LENGTH_SHORT_Z int *certInfoLength )
976  {
977  CERT_PKIUSER_INFO *certUserInfo = certInfoPtr->cCertUser;
978  char encUserInfo[ CRYPT_MAX_TEXTSIZE + 8 ];
979  BYTE userInfo[ 128 + 8 ], *userInfoPtr = userInfo;
980  int userInfoLength, encUserInfoLength, status;
981 
982  assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
983  assert( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
984  ( isWritePtr( certInfo, certInfoMaxLength ) ) );
985  assert( isWritePtr( certInfoLength, sizeof( int ) ) );
986 
987  REQUIRES( certInfoType == CRYPT_CERTINFO_PKIUSER_ID || \
988  certInfoType == CRYPT_CERTINFO_PKIUSER_ISSUEPASSWORD || \
989  certInfoType == CRYPT_CERTINFO_PKIUSER_REVPASSWORD );
990  REQUIRES( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
991  ( certInfo != NULL && \
992  certInfoMaxLength > 0 && \
993  certInfoMaxLength < MAX_INTLENGTH_SHORT ) );
994 
995  /* Clear return values */
996  if( certInfo != NULL )
997  memset( certInfo, 0, min( 16, certInfoMaxLength ) );
998  *certInfoLength = 0;
999 
1000  if( certInfoType == CRYPT_CERTINFO_PKIUSER_ID )
1001  {
1002  status = getCertAttributeComponent( certInfoPtr,
1004  userInfo, 128, &userInfoLength );
1005  ENSURES( cryptStatusOK( status ) );
1006  }
1007  else
1008  {
1009  userInfoPtr = ( certInfoType == CRYPT_CERTINFO_PKIUSER_ISSUEPASSWORD ) ? \
1010  certUserInfo->pkiIssuePW : certUserInfo->pkiRevPW;
1011  userInfoLength = PKIUSER_AUTHENTICATOR_SIZE;
1012  }
1013  status = encodePKIUserValue( encUserInfo, CRYPT_MAX_TEXTSIZE,
1014  &encUserInfoLength, userInfoPtr,
1015  userInfoLength,
1016  ( certInfoType == \
1017  CRYPT_CERTINFO_PKIUSER_ID ) ? 3 : 4 );
1018  zeroise( userInfo, CRYPT_MAX_TEXTSIZE );
1019  if( cryptStatusError( status ) )
1020  return( status );
1022  decodePKIUserValue( userInfo, 128, &userInfoLength,
1023  encUserInfo, encUserInfoLength ) ) );
1024  status = attributeCopyParams( certInfo, certInfoMaxLength,
1025  certInfoLength, encUserInfo,
1026  encUserInfoLength );
1027  zeroise( encUserInfo, CRYPT_MAX_TEXTSIZE );
1028 
1029  return( status );
1030  }
1031 #endif /* USE_PKIUSER */
1032 
1033 /****************************************************************************
1034 * *
1035 * Get a Certificate Component *
1036 * *
1037 ****************************************************************************/
1038 
1039 /* Get a certificate component */
1040 
1041 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 5 ) ) \
1042 int getCertComponentString( INOUT CERT_INFO *certInfoPtr,
1043  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE certInfoType,
1044  OUT_BUFFER_OPT( certInfoMaxLength, \
1045  *certInfoLength ) void *certInfo,
1046  IN_LENGTH_SHORT const int certInfoMaxLength,
1047  OUT_LENGTH_SHORT_Z int *certInfoLength )
1048  {
1049  const void *data = NULL;
1050  int dataLength = 0, status;
1051 
1052  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1053  assert( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
1054  ( certInfo != NULL && \
1055  certInfoMaxLength > 0 && \
1056  certInfoMaxLength < MAX_INTLENGTH_SHORT && \
1057  isWritePtr( certInfo, certInfoMaxLength ) ) );
1058  assert( isWritePtr( certInfoLength, sizeof( int ) ) );
1059 
1060  REQUIRES( isAttribute( certInfoType ) || \
1061  isInternalAttribute( certInfoType ) );
1062  REQUIRES( ( certInfo == NULL && certInfoMaxLength == 0 ) || \
1063  ( certInfo != NULL && \
1064  certInfoMaxLength > 0 && \
1065  certInfoMaxLength < MAX_INTLENGTH_SHORT ) );
1066 
1067  /* Clear return values */
1068  if( certInfo != NULL )
1069  memset( certInfo, 0, min( 16, certInfoMaxLength ) );
1070  *certInfoLength = 0;
1071 
1072  /* If it's a GeneralName or DN component, return it. These are
1073  special-case attribute values so they have to come before the
1074  general attribute-handling code */
1075  if( isGeneralNameComponent( certInfoType ) )
1076  {
1077  SELECTION_STATE selectionState;
1078  ATTRIBUTE_PTR *attributePtr = DUMMY_INIT_PTR;
1079  void *dataPtr;
1080 
1081  /* Find the requested GeneralName component and return it to the
1082  caller. Since selectGeneralNameComponent() changes the current
1083  selection within the GeneralName, we save the selection state
1084  around the call */
1085  saveSelectionState( selectionState, certInfoPtr );
1086  status = selectGeneralNameComponent( certInfoPtr, certInfoType );
1087  if( cryptStatusOK( status ) )
1088  attributePtr = certInfoPtr->attributeCursor;
1089  restoreSelectionState( selectionState, certInfoPtr );
1090  if( cryptStatusError( status ))
1091  return( status );
1092  ENSURES( attributePtr != NULL );
1093 
1094  /* Get the attribute component data */
1095  status = getAttributeDataPtr( attributePtr, &dataPtr, &dataLength );
1096  if( cryptStatusError( status ) )
1097  return( status );
1098  return( attributeCopyParams( certInfo, certInfoMaxLength,
1099  certInfoLength, dataPtr, dataLength ) );
1100  }
1101  if( isDNComponent( certInfoType ) )
1102  {
1103  int count = 0;
1104 
1105  /* If this is the currently selected item in the DN, the caller may
1106  be asking for the n-th occurrence rather than the initial one */
1107  if( certInfoPtr->currentSelection.dnComponent == certInfoType )
1108  count = certInfoPtr->currentSelection.dnComponentCount;
1109 
1110  /* Find the requested DN component and return it to the caller */
1111  status = selectDN( certInfoPtr, CRYPT_ATTRIBUTE_NONE,
1112  MUST_BE_PRESENT );
1113  if( cryptStatusError( status ) )
1114  return( status );
1115  return( getDNComponentValue( *certInfoPtr->currentSelection.dnPtr,
1116  certInfoType, count, certInfo,
1117  certInfoMaxLength, certInfoLength ) );
1118  }
1119 
1120  /* If it's standard certificate or CMS attribute, return it */
1121  if( ( certInfoType >= CRYPT_CERTINFO_FIRST_EXTENSION && \
1122  certInfoType <= CRYPT_CERTINFO_LAST_EXTENSION ) || \
1123  ( certInfoType >= CRYPT_CERTINFO_FIRST_CMS && \
1124  certInfoType <= CRYPT_CERTINFO_LAST_CMS ) )
1125  {
1126  return( getCertAttributeComponent( certInfoPtr, certInfoType,
1127  certInfo, certInfoMaxLength,
1128  certInfoLength ) );
1129  }
1130 
1131  /* If it's anything else, handle it specially */
1132  switch( certInfoType )
1133  {
1138  return( getCertHash( certInfoPtr, certInfoType, certInfo,
1139  certInfoMaxLength, certInfoLength ) );
1140 
1142  switch( certInfoPtr->type )
1143  {
1144 #ifdef USE_CERTREV
1145  case CRYPT_CERTTYPE_CRL:
1146  {
1147  const CERT_REV_INFO *certRevInfo = certInfoPtr->cCertRev;
1148 
1149  const REVOCATION_INFO *revInfoPtr = \
1150  ( certRevInfo->currentRevocation != NULL ) ? \
1151  certRevInfo->currentRevocation : certRevInfo->revocations;
1152 
1153  if( revInfoPtr != NULL )
1154  {
1155  data = revInfoPtr->id;
1156  dataLength = revInfoPtr->idLength;
1157  }
1158  break;
1159  }
1160 #endif /* USE_CERTREV */
1161 
1162 #ifdef USE_CERTREQ
1164  data = certInfoPtr->cCertReq->serialNumber;
1165  dataLength = certInfoPtr->cCertReq->serialNumberLength;
1166  break;
1167 #endif /* USE_CERTREQ */
1168 
1172  data = certInfoPtr->cCertCert->serialNumber;
1173  dataLength = certInfoPtr->cCertCert->serialNumberLength;
1174  break;
1175 
1176  default:
1177  retIntError();
1178  }
1179  return( attributeCopyParams( certInfo, certInfoMaxLength,
1180  certInfoLength, data, dataLength ) );
1181 
1184  if( certInfoPtr->startTime > MIN_CERT_TIME_VALUE )
1185  {
1186  data = &certInfoPtr->startTime;
1187  dataLength = sizeof( time_t );
1188  }
1189  return( attributeCopyParams( certInfo, certInfoMaxLength,
1190  certInfoLength, data, dataLength ) );
1191 
1194  if( certInfoPtr->endTime > MIN_CERT_TIME_VALUE )
1195  {
1196  data = &certInfoPtr->endTime;
1197  dataLength = sizeof( time_t );
1198  }
1199  return( attributeCopyParams( certInfo, certInfoMaxLength,
1200  certInfoLength, data, dataLength ) );
1201 
1202 #ifdef USE_CERT_OBSOLETE
1204  return( attributeCopyParams( certInfo, certInfoMaxLength,
1205  certInfoLength,
1206  certInfoPtr->cCertCert->issuerUniqueID,
1207  certInfoPtr->cCertCert->issuerUniqueIDlength ) );
1208 
1210  return( attributeCopyParams( certInfo, certInfoMaxLength,
1211  certInfoLength,
1212  certInfoPtr->cCertCert->subjectUniqueID,
1213  certInfoPtr->cCertCert->subjectUniqueIDlength ) );
1214 #endif /* USE_CERT_OBSOLETE */
1215 
1217  switch( certInfoPtr->type )
1218  {
1219 #ifdef USE_CERTREV
1220  case CRYPT_CERTTYPE_CRL:
1222  data = getRevocationTimePtr( certInfoPtr );
1223  break;
1224 #endif /* USE_CERTREV */
1225 
1226 #ifdef USE_CERTVAL
1228  data = getValidityTimePtr( certInfoPtr );
1229  break;
1230 #endif /* USE_CERTVAL */
1231 
1232  default:
1233  retIntError();
1234  }
1235  if( data != NULL )
1236  dataLength = sizeof( time_t );
1237  return( attributeCopyParams( certInfo, certInfoMaxLength,
1238  certInfoLength, data, dataLength ) );
1239 
1240 #ifdef USE_CERT_DNSTRING
1241  case CRYPT_CERTINFO_DN:
1242  {
1243  STREAM stream;
1244 
1245  /* Export the entire DN in string form */
1246  status = selectDN( certInfoPtr, CRYPT_ATTRIBUTE_NONE,
1247  MUST_BE_PRESENT );
1248  if( cryptStatusError( status ) )
1249  return( status );
1250  sMemOpenOpt( &stream, certInfo, certInfoMaxLength );
1251  status = writeDNstring( &stream,
1252  *certInfoPtr->currentSelection.dnPtr );
1253  if( cryptStatusOK( status ) )
1254  *certInfoLength = stell( &stream );
1255  sMemDisconnect( &stream );
1256  return( status );
1257  }
1258 #endif /* USE_CERT_DNSTRING */
1259 
1260 #ifdef USE_PKIUSER
1264  return( getPkiUserInfo( certInfoPtr, certInfoType, certInfo,
1265  certInfoMaxLength, certInfoLength ) );
1266 #endif /* USE_PKIUSER */
1267 
1268 #ifdef USE_CERTREV
1269  case CRYPT_IATTRIBUTE_CRLENTRY:
1270  return( getCrlEntry( certInfoPtr, certInfo, certInfoMaxLength,
1271  certInfoLength ) );
1272 #endif /* USE_CERTREV */
1273 
1274  case CRYPT_IATTRIBUTE_SUBJECT:
1275  /* Normally these attributes are only present for signed objects
1276  (i.e. ones that are in the high state) but CRMF requests
1277  acting as CMP revocation requests aren't signed so we have to
1278  set the ACLs to allow the attribute to be read in the low
1279  state as well. Since this only represents a programming
1280  error rather than a real access violation we catch it here
1281  with an assertion */
1282  assert( ( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION && \
1283  certInfoPtr->certificate == NULL ) || \
1284  certInfoPtr->certificate != NULL );
1285  return( attributeCopyParams( certInfo, certInfoMaxLength,
1286  certInfoLength,
1287  certInfoPtr->subjectDNptr,
1288  certInfoPtr->subjectDNsize ) );
1289 
1290  case CRYPT_IATTRIBUTE_ISSUER:
1291  return( attributeCopyParams( certInfo, certInfoMaxLength,
1292  certInfoLength,
1293  certInfoPtr->issuerDNptr,
1294  certInfoPtr->issuerDNsize ) );
1295 
1296  case CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER:
1297  return( getIAndS( certInfoPtr, certInfo, certInfoMaxLength,
1298  certInfoLength ) );
1299 
1300  case CRYPT_IATTRIBUTE_HOLDERNAME:
1301  return( getHolderName( certInfoPtr, certInfo, certInfoMaxLength,
1302  certInfoLength ) );
1303 
1304  case CRYPT_IATTRIBUTE_HOLDERURI:
1305  return( getHolderURI( certInfoPtr, certInfo, certInfoMaxLength,
1306  certInfoLength ) );
1307 
1308  case CRYPT_IATTRIBUTE_SPKI:
1309  {
1310  BYTE *dataStartPtr = certInfo;
1311 
1312  status = attributeCopyParams( certInfo, certInfoMaxLength,
1313  certInfoLength,
1314  certInfoPtr->publicKeyInfo,
1315  certInfoPtr->publicKeyInfoSize );
1316  if( cryptStatusError( status ) )
1317  return( status );
1318  if( dataStartPtr != NULL && dataStartPtr[ 0 ] == MAKE_CTAG( 6 ) )
1319  {
1320  /* Fix up CRMF braindamage */
1321  *dataStartPtr = BER_SEQUENCE;
1322  }
1323  return( CRYPT_OK );
1324  }
1325 
1326 #if defined( USE_CERTREV ) || defined( USE_CERTVAL )
1327  case CRYPT_IATTRIBUTE_RESPONDERURL:
1328  /* An RTCS/OCSP URL may be present if it was copied over from a
1329  certificate that's being checked, however if there wasn't any
1330  authorityInfoAccess information present then the URL won't
1331  have been initialised. Since this attribute isn't accessed
1332  via the normal certificate attribute mechanisms we have to
1333  explictly check for its non-presence */
1334  switch( certInfoPtr->type )
1335  {
1336 #ifdef USE_CERTREV
1338  if( certInfoPtr->cCertRev->responderUrl == NULL )
1339  return( CRYPT_ERROR_NOTFOUND );
1340  return( attributeCopyParams( certInfo, certInfoMaxLength,
1341  certInfoLength,
1342  certInfoPtr->cCertRev->responderUrl,
1343  certInfoPtr->cCertRev->responderUrlSize ) );
1344 #endif /* USE_CERTREV */
1345 
1346 #ifdef USE_CERTVAL
1348  if( certInfoPtr->cCertVal->responderUrl == NULL )
1349  return( CRYPT_ERROR_NOTFOUND );
1350  return( attributeCopyParams( certInfo, certInfoMaxLength,
1351  certInfoLength,
1352  certInfoPtr->cCertVal->responderUrl,
1353  certInfoPtr->cCertVal->responderUrlSize ) );
1354 #endif /* USE_CERTVAL */
1355 
1356  default:
1357  retIntError();
1358  }
1359 #endif /* USE_CERTREV || USE_CERTVAL */
1360 
1361 #ifdef USE_CERTREQ
1362  case CRYPT_IATTRIBUTE_AUTHCERTID:
1363  /* An authorising certificate identifier will be present if
1364  the request was handled by cryptlib but not if it came from
1365  an external source so we have to make sure that there's
1366  something actually present before we try to return it */
1367  if( !memcmp( certInfoPtr->cCertReq->authCertID,
1368  "\x00\x00\x00\x00\x00\x00\x00\x00", 8 ) )
1369  return( CRYPT_ERROR_NOTFOUND );
1370  return( attributeCopyParams( certInfo, certInfoMaxLength,
1371  certInfoLength,
1372  certInfoPtr->cCertReq->authCertID,
1373  KEYID_SIZE ) );
1374 #endif /* USE_CERTREQ */
1375 
1376  case CRYPT_IATTRIBUTE_ESSCERTID:
1377  return( getESSCertID( certInfoPtr, certInfo, certInfoMaxLength,
1378  certInfoLength ) );
1379  }
1380 
1381  retIntError();
1382  }
1383 #endif /* USE_CERTIFICATES */