cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
read.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Certificate Read Routines *
4 * Copyright Peter Gutmann 1996-2008 *
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 * Read Certificate Components *
23 * *
24 ****************************************************************************/
25 
26 /* Return from a certificate information read after encountering an error,
27  setting the extended error information if the error was caused by invalid
28  data. Although this isn't actually returned to the caller because the
29  certificate object isn't created, it allows more precise error diagnosis
30  for other routines */
31 
33 static int certErrorReturn( INOUT CERT_INFO *certInfoPtr,
34  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus,
35  IN_ERROR const int status )
36  {
37  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
38 
39  REQUIRES( errorLocus > CRYPT_ATTRIBUTE_NONE && \
40  errorLocus < CRYPT_IATTRIBUTE_LAST );
41  REQUIRES( cryptStatusError( status ) );
42 
43  /* Catch any attempts to set the error locus to internal attributes */
44  if( errorLocus > CRYPT_ATTRIBUTE_LAST )
45  {
46  DEBUG_DIAG(( "Caught attempt to set invalid error locus" ));
47  assert( DEBUG_WARN );
48  return( status );
49  }
50 
51  if( status == CRYPT_ERROR_BADDATA || status == CRYPT_ERROR_UNDERFLOW )
52  setErrorInfo( certInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_VALUE );
53  return( status );
54  }
55 
56 /* Read version information */
57 
58 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
59 static int readVersion( INOUT STREAM *stream,
60  INOUT CERT_INFO *certInfoPtr,
61  IN_TAG const int tag,
62  IN_RANGE( 1, 5 ) const int maxVersion )
63  {
64  long version;
65  int status;
66 
67  assert( isWritePtr( stream, sizeof( STREAM ) ) );
68  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
69 
70  REQUIRES( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
71  REQUIRES( maxVersion >= 1 && maxVersion <= 5 );
72 
73  /* Versions can be represented in one of three ways:
74 
75  1. version INTEGER
76  2. version INTEGER DEFAULT(1)
77  3. version [tag] INTEGER DEFAULT (1)
78 
79  To handle this we check for the required tags for versions with
80  DEFAULT values and exit if they're not found, setting the version to
81  1 first */
82  certInfoPtr->version = 1;
83  if( tag != DEFAULT_TAG )
84  {
85  if( tag == BER_INTEGER )
86  {
87  /* INTEGER DEFAULT (1), if we don't find this we're done */
88  if( peekTag( stream ) != BER_INTEGER )
89  return( CRYPT_OK );
90  }
91  else
92  {
93  /* [tag] INTEGER DEFAULT (1), if we don't find this we're done */
94  if( peekTag( stream ) != MAKE_CTAG( tag ) )
95  return( CRYPT_OK );
96  status = readConstructed( stream, NULL, tag );
97  if( cryptStatusError( status ) )
98  return( status );
99  }
100  }
101 
102  /* We've definitely got a version number present, process it */
103  status = readShortInteger( stream, &version );
104  if( cryptStatusError( status ) )
105  return( status );
106  if( version < 0 || version > maxVersion )
107  return( CRYPT_ERROR_BADDATA );
108  certInfoPtr->version = version + 1; /* Zero-based */
109 
110  return( CRYPT_OK );
111  }
112 
113 /* Read a certificate serial number */
114 
115 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
116 static int readSerialNumber( INOUT STREAM *stream,
117  INOUT CERT_INFO *certInfoPtr,
118  IN_TAG const int tag )
119  {
121  int integerLength, status;
122 
123  assert( isWritePtr( stream, sizeof( STREAM ) ) );
124  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
125 
126  REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
127 
128  /* Read the integer component of the serial number */
129  status = readIntegerTag( stream, integer, MAX_SERIALNO_SIZE,
130  &integerLength, tag );
131  if( cryptStatusError( status ) )
132  return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_SERIALNUMBER,
133  status ) );
134 
135  /* Some certificates may have a serial number of zero, which is turned
136  into a zero-length integer by the ASN.1 read code since it truncates
137  leading zeroes that are added due to ASN.1 encoding requirements. If
138  we get a zero-length integer we turn it into a single zero byte */
139  if( integerLength <= 0 )
140  {
141  integer[ 0 ] = 0;
142  integerLength = 1;
143  }
144 
145  /* Copy the data across for the caller */
146  return( setSerialNumber( certInfoPtr, integer, integerLength ) );
147  }
148 
149 /* Read DN information and remember the encoded DN data so that we can copy
150  it (complete with any encoding errors) to the issuer DN field of
151  anything that we sign */
152 
153 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
154 static int readSubjectDN( INOUT STREAM *stream,
155  INOUT CERT_INFO *certInfoPtr )
156  {
157  int length, status;
158 
159  assert( isWritePtr( stream, sizeof( STREAM ) ) );
160  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
161 
162  status = getStreamObjectLength( stream, &length );
163  if( cryptStatusOK( status ) )
164  {
165  certInfoPtr->subjectDNsize = length;
166  status = sMemGetDataBlock( stream, &certInfoPtr->subjectDNptr,
167  length );
168  }
169  if( cryptStatusOK( status ) )
170  status = readDN( stream, &certInfoPtr->subjectName );
171  if( cryptStatusError( status ) )
172  {
173  return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_SUBJECTNAME,
174  status ) );
175  }
176  return( CRYPT_OK );
177  }
178 
179 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
180 static int readIssuerDN( INOUT STREAM *stream,
181  INOUT CERT_INFO *certInfoPtr )
182  {
183  int length, status;
184 
185  assert( isWritePtr( stream, sizeof( STREAM ) ) );
186  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
187 
188  status = getStreamObjectLength( stream, &length );
189  if( cryptStatusOK( status ) )
190  {
191  certInfoPtr->issuerDNsize = length;
192  status = sMemGetDataBlock( stream, &certInfoPtr->issuerDNptr,
193  length );
194  }
195  if( cryptStatusOK( status ) )
196  status = readDN( stream, &certInfoPtr->issuerName );
197  if( cryptStatusError( status ) )
198  {
199  return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_ISSUERNAME,
200  status ) );
201  }
202  return( CRYPT_OK );
203  }
204 
205 /* Read public-key information */
206 
207 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
208 static int readPublicKeyInfo( INOUT STREAM *stream,
209  INOUT CERT_INFO *certInfoPtr )
210  {
211  int length, status;
212 
213  assert( isWritePtr( stream, sizeof( STREAM ) ) );
214  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
215 
216  /* Record a reference to the public-key data */
217  status = getStreamObjectLength( stream, &length );
218  if( cryptStatusOK( status ) )
219  {
220  certInfoPtr->publicKeyInfoSize = length;
221  status = sMemGetDataBlock( stream, &certInfoPtr->publicKeyInfo,
222  length );
223  }
224  if( cryptStatusError( status ) )
225  {
226  return( certErrorReturn( certInfoPtr,
228  status ) );
229  }
230 
231  /* Import or read (for a data-only certificate) the public key
232  information */
233  if( certInfoPtr->flags & CERT_FLAG_DATAONLY )
234  {
235  int parameterLength;
236 
237  /* We're doing deferred handling of the public key, skip it for now.
238  Because of weird tagging in things like CRMF objects we have to
239  read the information as a generic hole rather than a normal
240  SEQUENCE.
241 
242  Unlike a standard read via iCryptReadSubjectPublicKey() this
243  doesn't catch the use of too-short key parameters because we'd
244  have to duplicate most of the code that
245  iCryptReadSubjectPublicKey() calls in order to read the key
246  components, however data-only certificates are only created for
247  use in conjunction with encryption contexts so the context create
248  will catch the use of too-short parameters */
249  readGenericHole( stream, NULL, 4, DEFAULT_TAG );
250  status = readAlgoIDparam( stream, &certInfoPtr->publicKeyAlgo,
251  &parameterLength, ALGOID_CLASS_PKC );
252  if( cryptStatusOK( status ) )
253  {
254  if( parameterLength > 0 )
255  sSkip( stream, parameterLength );
256  status = readUniversal( stream );
257  }
258  }
259  else
260  {
261  status = iCryptReadSubjectPublicKey( stream,
262  &certInfoPtr->iPubkeyContext,
264  if( cryptStatusOK( status ) )
265  {
266  status = krnlSendMessage( certInfoPtr->iPubkeyContext,
268  &certInfoPtr->publicKeyAlgo,
270  }
271  }
272  if( cryptStatusError( status ) )
273  {
274  return( certErrorReturn( certInfoPtr,
276  status ) );
277  }
278 
279  return( CRYPT_OK );
280  }
281 
282 /****************************************************************************
283 * *
284 * Read Certificate Objects *
285 * *
286 ****************************************************************************/
287 
288 /* Read validity information */
289 
290 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
291 static int readValidity( INOUT STREAM *stream,
292  INOUT CERT_INFO *certInfoPtr )
293  {
294  int status;
295 
296  assert( isWritePtr( stream, sizeof( STREAM ) ) );
297  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
298 
299  status = readSequence( stream, NULL );
300  if( cryptStatusError( status ) )
301  return( status );
302  if( peekTag( stream ) == BER_TIME_UTC )
303  status = readUTCTime( stream, &certInfoPtr->startTime );
304  else
305  status = readGeneralizedTime( stream, &certInfoPtr->startTime );
306  if( cryptStatusError( status ) )
307  {
308  return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_VALIDFROM,
309  status ) );
310  }
311  if( peekTag( stream ) == BER_TIME_UTC )
312  status = readUTCTime( stream, &certInfoPtr->endTime );
313  else
314  status = readGeneralizedTime( stream, &certInfoPtr->endTime );
315  if( cryptStatusError( status ) )
316  {
317  return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_VALIDTO,
318  status ) );
319  }
320  return( CRYPT_OK );
321  }
322 
323 #ifdef USE_CERT_OBSOLETE
324 
325 /* Read a uniqueID */
326 
327 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
328 static int readUniqueID( INOUT STREAM *stream,
329  INOUT CERT_INFO *certInfoPtr,
331  {
332  int length, status;
333 
334  assert( isWritePtr( stream, sizeof( STREAM ) ) );
335  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
336 
339 
340  /* Read the length of the unique ID, allocate room for it, and read it
341  into the certificate */
342  status = readBitStringHole( stream, &length, 1,
343  ( type == CRYPT_CERTINFO_ISSUERUNIQUEID ) ? \
346  if( cryptStatusOK( status ) && ( length < 1 || length > 1024 ) )
347  status = CRYPT_ERROR_BADDATA;
348  if( cryptStatusOK( status ) )
349  {
350  void *bufPtr;
351 
352  if( ( bufPtr = clDynAlloc( "readUniqueID", length ) ) == NULL )
353  return( CRYPT_ERROR_MEMORY );
354  if( type == CRYPT_CERTINFO_SUBJECTUNIQUEID )
355  {
356  certInfoPtr->cCertCert->subjectUniqueID = bufPtr;
357  certInfoPtr->cCertCert->subjectUniqueIDlength = length;
358  }
359  else
360  {
361  certInfoPtr->cCertCert->issuerUniqueID = bufPtr;
362  certInfoPtr->cCertCert->issuerUniqueIDlength = length;
363  }
364  status = sread( stream, bufPtr, length );
365  }
366  if( cryptStatusError( status ) )
367  return( certErrorReturn( certInfoPtr, type, status ) );
368  return( CRYPT_OK );
369  }
370 #else
371  #define readUniqueID( stream, certInfoPtr, type ) readUniversal( stream );
372 #endif /* USE_CERT_OBSOLETE */
373 
374 /* Read certificate information:
375 
376  CertificateInfo ::= SEQUENCE {
377  version [ 0 ] EXPLICIT INTEGER DEFAULT(0),
378  serialNumber INTEGER,
379  signature AlgorithmIdentifier,
380  issuer Name
381  validity Validity,
382  subject Name,
383  subjectPublicKeyInfo SubjectPublicKeyInfo,
384  extensions [ 3 ] Extensions OPTIONAL
385  } */
386 
387 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
388 static int readCertInfo( INOUT STREAM *stream,
389  INOUT CERT_INFO *certInfoPtr )
390  {
391  CRYPT_ALGO_TYPE dummyAlgo;
392  int length, endPos, dummyInt, status;
393 
394  assert( isWritePtr( stream, sizeof( STREAM ) ) );
395  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
396 
397  /* Read the outer SEQUENCE and version number if it's present */
398  status = readSequence( stream, &length );
399  if( cryptStatusError( status ) )
400  return( status );
401  endPos = stell( stream ) + length;
402  status = readVersion( stream, certInfoPtr, CTAG_CE_VERSION, 3 );
403  if( cryptStatusError( status ) )
404  return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_VERSION,
405  status ) );
406 
407  /* Read the serial number and signature algorithm information. The
408  algorithm information was included to avert a somewhat obscure attack
409  that isn't possible anyway because of the way the signature data is
410  encoded in PKCS #1 sigs (although it's still possible for some of the
411  ISO signature types) so there's no need to record it, however we
412  record it because CMP uses the hash algorithm in the certificate as
413  an implicit indicator of the hash algorithm that it uses for CMP
414  messages (!!) */
415  status = readSerialNumber( stream, certInfoPtr, DEFAULT_TAG );
416  if( cryptStatusOK( status ) )
417  {
418  status = readAlgoIDex( stream, &dummyAlgo, \
419  &certInfoPtr->cCertCert->hashAlgo,
420  &dummyInt, ALGOID_CLASS_PKCSIG );
421  }
422  if( cryptStatusError( status ) )
423  return( status );
424 
425  /* Read the issuer name, validity information, and subject name */
426  status = readIssuerDN( stream, certInfoPtr );
427  if( cryptStatusOK( status ) )
428  status = readValidity( stream, certInfoPtr );
429  if( cryptStatusOK( status ) )
430  status = readSubjectDN( stream, certInfoPtr );
431  if( cryptStatusError( status ) )
432  return( status );
433 
434  /* Check to see whether it's a self-signed certificate */
435  if( certInfoPtr->issuerDNsize == certInfoPtr->subjectDNsize && \
436  !memcmp( certInfoPtr->issuerDNptr, certInfoPtr->subjectDNptr,
437  certInfoPtr->subjectDNsize ) )
438  certInfoPtr->flags |= CERT_FLAG_SELFSIGNED;
439 
440  /* Read the public key information */
441  status = readPublicKeyInfo( stream, certInfoPtr );
442  if( cryptStatusError( status ) )
443  return( status );
444 
445  /* Read the issuer and subject unique ID's if there are any present */
446  if( peekTag( stream ) == MAKE_CTAG_PRIMITIVE( CTAG_CE_ISSUERUNIQUEID ) )
447  {
448  status = readUniqueID( stream, certInfoPtr,
450  if( cryptStatusError( status ) )
451  return( status );
452  }
453  if( peekTag( stream ) == MAKE_CTAG_PRIMITIVE( CTAG_CE_SUBJECTUNIQUEID ) )
454  {
455  status = readUniqueID( stream, certInfoPtr,
457  if( cryptStatusError( status ) )
458  return( status );
459  }
460 
461  /* Read the extensions if there are any present. Because some
462  certificates will have broken encoding of lengths we allow for a bit
463  of slop for software that gets the length encoding wrong by a few
464  bytes */
465  if( stell( stream ) < endPos - MIN_ATTRIBUTE_SIZE )
466  {
467  status = readAttributes( stream, &certInfoPtr->attributes,
468  CRYPT_CERTTYPE_CERTIFICATE, endPos - stell( stream ),
469  &certInfoPtr->errorLocus, &certInfoPtr->errorType );
470  if( cryptStatusError( status ) )
471  return( status );
472  }
473 
474  /* Fix up any problems in attributes */
475  return( fixAttributes( certInfoPtr ) );
476  }
477 
478 /* Read attribute certificate information. There are two variants of this,
479  v1 attributes certificates that were pretty much never used (the fact
480  that no-one had bothered to define any attributes to be used with them
481  didn't help here) and v2 attribute certificates that are also almost
482  never used but are newer, we read v2 certificates. The original v1
483  attribute certificate format was:
484 
485  AttributeCertificateInfo ::= SEQUENCE {
486  version INTEGER DEFAULT(0),
487  owner [ 1 ] Name,
488  issuer Name,
489  signature AlgorithmIdentifier,
490  serialNumber INTEGER,
491  validity Validity,
492  attributes SEQUENCE OF Attribute,
493  extensions Extensions OPTIONAL
494  }
495 
496  In v2 this changed to:
497 
498  AttributeCertificateInfo ::= SEQUENCE {
499  version INTEGER (1),
500  holder SEQUENCE {
501  entityNames [ 1 ] SEQUENCE OF {
502  entityName[ 4 ] EXPLICIT Name
503  },
504  }
505  issuer [ 0 ] SEQUENCE {
506  issuerNames SEQUENCE OF {
507  issuerName[ 4 ] EXPLICIT Name
508  },
509  }
510  signature AlgorithmIdentifier,
511  serialNumber INTEGER,
512  validity SEQUENCE {
513  notBefore GeneralizedTime,
514  notAfter GeneralizedTime
515  },
516  attributes SEQUENCE OF Attribute,
517  extensions Extensions OPTIONAL
518  } */
519 
520 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
521 static int readAttributeCertInfo( INOUT STREAM *stream,
522  INOUT CERT_INFO *certInfoPtr )
523  {
524  int length, endPos, innerEndPos, status;
525 
526  assert( isWritePtr( stream, sizeof( STREAM ) ) );
527  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
528 
529  /* Read the outer SEQUENCE and version number */
530  status = readSequence( stream, &length );
531  if( cryptStatusError( status ) )
532  return( status );
533  endPos = stell( stream ) + length;
534  status = readVersion( stream, certInfoPtr, BER_INTEGER, 2 );
535  if( cryptStatusError( status ) )
536  return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_VERSION,
537  status ) );
538 
539  /* Read the owner and issuer names */
540  status = readSequence( stream, &length );
541  if( cryptStatusError( status ) )
542  return( status );
543  innerEndPos = stell( stream ) + length;
544  if( peekTag( stream ) == MAKE_CTAG( CTAG_AC_HOLDER_BASECERTIFICATEID ) )
545  {
546  status = readUniversal( stream );
547  if( cryptStatusError( status ) )
548  return( status );
549  }
550  if( stell( stream ) < innerEndPos && \
551  peekTag( stream ) == MAKE_CTAG( CTAG_AC_HOLDER_ENTITYNAME ) )
552  {
553  readConstructed( stream, NULL, CTAG_AC_HOLDER_ENTITYNAME );
554  readConstructed( stream, NULL, 4 );
555  status = readSubjectDN( stream, certInfoPtr );
556  if( cryptStatusError( status ) )
557  return( status );
558  }
559  if( stell( stream ) < innerEndPos && \
560  peekTag( stream ) == MAKE_CTAG( CTAG_AC_HOLDER_OBJECTDIGESTINFO ) )
561  {
562  /* This is a complicated structure that in effect encodes a generic
563  hole reference to "other", for now we just skip it until we can
564  find an example of something that actually use it */
565  status = readUniversal( stream );
566  if( cryptStatusError( status ) )
567  return( status );
568  }
569  status = readConstructed( stream, &length, 0 );
570  if( cryptStatusError( status ) )
571  return( status );
572  innerEndPos = stell( stream ) + length;
573  if( peekTag( stream ) == BER_SEQUENCE )
574  {
575  readSequence( stream, NULL );
576  readConstructed( stream, NULL, 4 );
577  status = readIssuerDN( stream, certInfoPtr );
578  if( cryptStatusError( status ) )
579  return( status );
580  }
581  if( stell( stream ) < innerEndPos && \
582  peekTag( stream ) == MAKE_CTAG( CTAG_AC_ISSUER_BASECERTIFICATEID ) )
583  {
584  status = readUniversal( stream );
585  if( cryptStatusError( status ) )
586  return( status );
587  }
588  if( stell( stream ) < innerEndPos && \
589  peekTag( stream ) == MAKE_CTAG( CTAG_AC_ISSUER_OBJECTDIGESTINFO ) )
590  {
591  /* See the comment for the owner objectDigectInfo above */
592  status = readUniversal( stream );
593  if( cryptStatusError( status ) )
594  return( status );
595  }
596 
597  /* Skip the signature algorithm information. This was included to avert
598  a somewhat obscure attack that isn't possible anyway because of the
599  way the signature data is encoded in PKCS #1 sigs (although it's still
600  possible for some of the ISO signature types) so there's no need to
601  record it */
602  readUniversal( stream );
603 
604  /* Read the serial number and validity information */
605  status = readSerialNumber( stream, certInfoPtr, DEFAULT_TAG );
606  if( cryptStatusOK( status ) )
607  status = readValidity( stream, certInfoPtr );
608  if( cryptStatusError( status ) )
609  return( status );
610 
611  /* Skip the attributes for now since these aren't really defined yet */
612  status = readUniversal( stream );
613  if( cryptStatusError( status ) )
614  return( status );
615 
616  /* Read the issuer unique ID if there's one present */
617  if( peekTag( stream ) == BER_BITSTRING )
618  {
619  status = readUniqueID( stream, certInfoPtr,
621  if( cryptStatusError( status ) )
622  return( status );
623  }
624 
625  /* Read the extensions if there are any present. Because some
626  certificates will have broken encoding of lengths we allow for a bit
627  of slop for software that gets the length encoding wrong by a few
628  bytes */
629  if( stell( stream ) < endPos - MIN_ATTRIBUTE_SIZE )
630  {
631  status = readAttributes( stream, &certInfoPtr->attributes,
632  CRYPT_CERTTYPE_ATTRIBUTE_CERT, endPos - stell( stream ),
633  &certInfoPtr->errorLocus, &certInfoPtr->errorType );
634  }
635 
636  return( status );
637  }
638 
639 /****************************************************************************
640 * *
641 * Read CRL Objects *
642 * *
643 ****************************************************************************/
644 
645 #ifdef USE_CERTREV
646 
647 /* Read CRL information:
648 
649  CRLInfo ::= SEQUENCE {
650  version INTEGER DEFAULT(0),
651  signature AlgorithmIdentifier,
652  issuer Name,
653  thisUpdate UTCTime,
654  nextUpdate UTCTime OPTIONAL,
655  revokedCertificates SEQUENCE OF RevokedCerts,
656  extensions [ 0 ] Extensions OPTIONAL
657  }
658 
659  We read various lengths as long values since CRLs can get quite large */
660 
661 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
662 static int readCRLInfo( INOUT STREAM *stream,
663  INOUT CERT_INFO *certInfoPtr )
664  {
665  CERT_REV_INFO *certRevInfo = certInfoPtr->cCertRev;
666  long length, endPos;
667  int status;
668 
669  assert( isWritePtr( stream, sizeof( STREAM ) ) );
670  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
671 
672  /* If it's a standalone CRL entry, read the single entry and return */
673  if( certInfoPtr->flags & CERT_FLAG_CRLENTRY )
674  {
675  return( readCRLentry( stream, &certRevInfo->revocations, 1,
676  &certInfoPtr->errorLocus,
677  &certInfoPtr->errorType ) );
678  }
679 
680  /* Read the outer SEQUENCE and version number if it's present */
681  status = readLongSequence( stream, &length );
682  if( cryptStatusError( status ) )
683  return( status );
684  if( length == CRYPT_UNUSED )
685  {
686  /* If it's an (invalid) indefinite-length encoding we can't do
687  anything with it */
688  return( CRYPT_ERROR_BADDATA );
689  }
690  endPos = stell( stream ) + length;
691  status = readVersion( stream, certInfoPtr, BER_INTEGER, 2 );
692  if( cryptStatusError( status ) )
693  return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_VERSION,
694  status ) );
695 
696  /* Skip the signature algorithm information. This was included to avert
697  a somewhat obscure attack that isn't possible anyway because of the
698  way the signature data is encoded in PKCS #1 sigs (although it's still
699  possible for some of the ISO signature types) so there's no need to
700  record it */
701  readUniversal( stream );
702 
703  /* Read the issuer name, update time, and optional next update time */
704  status = readIssuerDN( stream, certInfoPtr );
705  if( cryptStatusError( status ) )
706  return( status );
707  status = readUTCTime( stream, &certInfoPtr->startTime );
708  if( cryptStatusError( status ) )
709  return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_THISUPDATE,
710  status ) );
711  if( peekTag( stream ) == BER_TIME_UTC )
712  {
713  status = readUTCTime( stream, &certInfoPtr->endTime );
714  if( cryptStatusError( status ) )
715  return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_NEXTUPDATE,
716  status ) );
717  }
718 
719  /* Read the SEQUENCE OF revoked certificates and make the currently
720  selected one the start of the list */
721  if( stell( stream ) < endPos - MIN_ATTRIBUTE_SIZE && \
722  peekTag( stream ) == BER_SEQUENCE )
723  {
724  int noCrlEntries;
725 
726  /* The following loop is a bit tricky to failsafe because it's
727  actually possible to encounter real-world 100MB CRLs that the
728  failsafe would otherwise identify as an error. Because CRLs can
729  range so far outside what would be considered sane we can't
730  really bound the loop in any way except at a fairly generic
731  maximum-integer value */
732  status = readLongSequence( stream, &length );
733  if( cryptStatusError( status ) )
734  return( status );
735  if( length == CRYPT_UNUSED )
736  {
737  /* If it's an (invalid) indefinite-length encoding we can't do
738  anything with it */
739  return( CRYPT_ERROR_BADDATA );
740  }
741  for( noCrlEntries = 0;
742  cryptStatusOK( status ) && length > MIN_ATTRIBUTE_SIZE && \
743  noCrlEntries < FAILSAFE_ITERATIONS_MAX;
744  noCrlEntries++ )
745  {
746  const long innerStartPos = stell( stream );
747 
748  REQUIRES( innerStartPos > 0 && innerStartPos < MAX_INTLENGTH );
749 
750  status = readCRLentry( stream, &certRevInfo->revocations,
751  noCrlEntries, &certInfoPtr->errorLocus,
752  &certInfoPtr->errorType );
753  if( cryptStatusOK( status ) )
754  length -= stell( stream ) - innerStartPos;
755  }
756  ENSURES( noCrlEntries < FAILSAFE_ITERATIONS_MAX );
757  if( cryptStatusError( status ) )
758  {
759  /* The invalid attribute isn't quite a user certificate, but
760  it's the data that arose from a user certificate so it's the
761  most appropriate locus for the error */
762  return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
763  status ) );
764  }
765  certRevInfo->currentRevocation = certRevInfo->revocations;
766  }
767 
768  /* Read the extensions if there are any present. Because some CRL's
769  will have broken encoding of lengths we allow for a bit of slop for
770  software that gets the length encoding wrong by a few bytes */
771  if( stell( stream ) < endPos - MIN_ATTRIBUTE_SIZE )
772  {
773  status = readAttributes( stream, &certInfoPtr->attributes,
774  CRYPT_CERTTYPE_CRL, endPos - stell( stream ),
775  &certInfoPtr->errorLocus, &certInfoPtr->errorType );
776  if( cryptStatusError( status ) )
777  return( status );
778  }
779 
780  /* Fix up any problems in attributes */
781  return( fixAttributes( certInfoPtr ) );
782  }
783 
784 #endif /* USE_CERTREV */
785 
786 /****************************************************************************
787 * *
788 * Read Certificate Request Objects *
789 * *
790 ****************************************************************************/
791 
792 #ifdef USE_CERTREQ
793 
794 /* Read validity information. Despite being a post-Y2K standard, CRMF still
795  allows the non-Y2K UTCTime format to be used for dates so we have to
796  accomodate both date types. In addition both values are optional so we
797  only try and read them if we see their tags */
798 
799 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
800 static int readCrmfValidity( INOUT STREAM *stream,
801  INOUT CERT_INFO *certInfoPtr )
802  {
803  int tag, status;
804 
805  assert( isWritePtr( stream, sizeof( STREAM ) ) );
806  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
807 
808  status = readConstructed( stream, NULL, CTAG_CF_VALIDITY );
809  if( cryptStatusError( status ) )
810  return( status );
811  tag = peekTag( stream );
812  if( cryptStatusError( tag ) )
813  return( tag );
814  if( tag == MAKE_CTAG( 0 ) )
815  {
816  readConstructed( stream, NULL, 0 );
817  if( peekTag( stream ) == BER_TIME_UTC )
818  status = readUTCTime( stream, &certInfoPtr->startTime );
819  else
820  status = readGeneralizedTime( stream, &certInfoPtr->startTime );
821  if( cryptStatusError( status ) )
822  {
823  return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_VALIDFROM,
824  status ) );
825  }
826  tag = peekTag( stream );
827  if( cryptStatusError( tag ) )
828  return( tag );
829  }
830  if( tag == MAKE_CTAG( 1 ) )
831  {
832  readConstructed( stream, NULL, 1 );
833  if( peekTag( stream ) == BER_TIME_UTC )
834  status = readUTCTime( stream, &certInfoPtr->endTime );
835  else
836  status = readGeneralizedTime( stream, &certInfoPtr->endTime );
837  if( cryptStatusError( status ) )
838  {
839  return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_VALIDTO,
840  status ) );
841  }
842  }
843  return( status );
844  }
845 
846 /* CRMF requests can include a large amount of unnecessary junk that no-one
847  (including the RFC authors, when asked) can explain and the semantics of
848  which are at best undefined (version) and at worst dangerous
849  (serialNumber). The best way to deal with them on the off chance that
850  the client has specified them is to skip the unneeded information until
851  we get to something that we can use */
852 
854 static int skipCrmfJunk( INOUT STREAM *stream,
855  IN_LENGTH_SHORT const int endPos,
856  IN_TAG_ENCODED const int terminatorTag,
857  IN_TAG_ENCODED const int optTerminatorTag1,
858  IN_TAG_ENCODED const int optTerminatorTag2 )
859  {
860  int fieldsProcessed;
861 
862  assert( isWritePtr( stream, sizeof( STREAM ) ) );
863 
864  REQUIRES( endPos > 0 && endPos < MAX_INTLENGTH_SHORT );
865  REQUIRES( terminatorTag > 0 && terminatorTag <= MAX_TAG );
866  REQUIRES( ( optTerminatorTag1 == NO_TAG ) || \
867  ( optTerminatorTag1 > 0 && optTerminatorTag1 <= MAX_TAG ) );
868  REQUIRES( ( optTerminatorTag2 == NO_TAG ) || \
869  ( optTerminatorTag2 > 0 && optTerminatorTag2 <= MAX_TAG ) );
870 
871  /* Skip any junk until we get to a field that we're interested in */
872  for( fieldsProcessed = 0;
873  stell( stream ) < endPos - MIN_ATTRIBUTE_SIZE && \
874  fieldsProcessed < 8;
875  fieldsProcessed++ )
876  {
877  int tag, status;
878 
879  /* Check whether we've reached any of requested the terminator
880  tags */
881  tag = peekTag( stream );
882  if( cryptStatusError( tag ) )
883  return( tag );
884  if( tag == terminatorTag )
885  break;
886  if( optTerminatorTag1 != NO_TAG && tag == optTerminatorTag1 )
887  break;
888  if( optTerminatorTag2 != NO_TAG && tag == optTerminatorTag2 )
889  break;
890 
891  /* Skip this item */
892  status = readUniversal( stream );
893  if( cryptStatusError( status ) )
894  return( status );
895  }
896  if( fieldsProcessed >= 8 )
897  {
898  /* We should have hit something useful by this point */
899  return( CRYPT_ERROR_BADDATA );
900  }
901 
902  return( CRYPT_OK );
903  }
904 
905 /* Read certificate request information:
906 
907  CertificationRequestInfo ::= SEQUENCE {
908  version INTEGER (0),
909  subject Name,
910  subjectPublicKeyInfo SubjectPublicKeyInfo,
911  attributes [ 0 ] SET OF Attribute
912  }
913 
914  If extensions are present they are encoded as:
915 
916  SEQUENCE { -- Attribute from X.501
917  OBJECT IDENTIFIER {pkcs-9 14}, -- type
918  SET OF { -- values
919  SEQUENCE OF { -- ExtensionReq from CMMF draft
920  <X.509v3 extensions>
921  }
922  }
923  } */
924 
925 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
926 static int readCertRequestInfo( INOUT STREAM *stream,
927  INOUT CERT_INFO *certInfoPtr )
928  {
929  long endPos;
930  int length, status;
931 
932  assert( isWritePtr( stream, sizeof( STREAM ) ) );
933  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
934 
935  /* Skip the outer SEQUENCE and read the version number */
936  status = readSequence( stream, &length );
937  if( cryptStatusError( status ) )
938  return( status );
939  endPos = stell( stream ) + length;
940  status = readVersion( stream, certInfoPtr, DEFAULT_TAG, 1 );
941  if( cryptStatusError( status ) )
942  return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_VERSION,
943  status ) );
944 
945  /* Read the subject name and public key information */
946  status = readSubjectDN( stream, certInfoPtr );
947  if( cryptStatusOK( status ) )
948  status = readPublicKeyInfo( stream, certInfoPtr );
949  if( cryptStatusError( status ) )
950  return( status );
951 
952  /* Read the attributes */
953  if( stell( stream ) < endPos - MIN_ATTRIBUTE_SIZE && \
954  peekTag( stream ) == MAKE_CTAG( CTAG_CR_ATTRIBUTES ) )
955  {
956  status = readConstructed( stream, &length, CTAG_CR_ATTRIBUTES );
957  if( cryptStatusOK( status ) && length > MIN_ATTRIBUTE_SIZE )
958  {
959  status = readAttributes( stream, &certInfoPtr->attributes,
961  &certInfoPtr->errorLocus,
962  &certInfoPtr->errorType );
963  }
964  if( cryptStatusError( status ) )
965  return( status );
966  }
967 
968  /* Certification requests are always self-signed */
969  certInfoPtr->flags |= CERT_FLAG_SELFSIGNED;
970 
971  /* Fix up any problems in attributes */
972  return( fixAttributes( certInfoPtr ) );
973  }
974 
975 /* Read CRMF certificate request information:
976 
977  CertReq ::= SEQUENCE {
978  certReqID INTEGER (0),
979  certTemplate SEQUENCE {
980  validity [ 4 ] SEQUENCE {
981  validFrom [ 0 ] EXPLICIT GeneralizedTime OPTIONAL,
982  validTo [ 1 ] EXPLICIT GeneralizedTime OPTIONAL
983  } OPTIONAL,
984  subject [ 5 ] EXPLICIT Name OPTIONAL,
985  publicKey [ 6 ] SubjectPublicKeyInfo,
986  extensions [ 9 ] SET OF Attribute OPTIONAL
987  }
988  }
989 
990  We enforce the requirement that the request must contain at least a
991  subject DN and a public key */
992 
993 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
994 static int readCrmfRequestInfo( INOUT STREAM *stream,
995  INOUT CERT_INFO *certInfoPtr )
996  {
997  int tag, length, endPos, status;
998 
999  assert( isWritePtr( stream, sizeof( STREAM ) ) );
1000  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1001 
1002  /* Skip the outer SEQUENCE, request ID, and inner SEQUENCE */
1003  status = readSequence( stream, &length );
1004  if( cryptStatusError( status ) )
1005  return( status );
1006  endPos = stell( stream ) + length;
1007  readUniversal( stream );
1008  status = readSequence( stream, NULL );
1009  if( cryptStatusError( status ) )
1010  return( status );
1011 
1012  /* Skip any junk before the Validity, SubjectName, or
1013  SubjectPublicKeyInfo */
1014  status = skipCrmfJunk( stream, endPos,
1018  if( cryptStatusError( status ) )
1019  return( status );
1020 
1021  /* If there's validity data present, read it */
1022  if( peekTag( stream ) == MAKE_CTAG( CTAG_CF_VALIDITY ) )
1023  {
1024  status = readCrmfValidity( stream, certInfoPtr );
1025  if( cryptStatusError( status ) )
1026  return( status );
1027  }
1028 
1029  /* If there's a subject name present, read it */
1030  if( peekTag( stream ) == MAKE_CTAG( CTAG_CF_SUBJECT ) )
1031  {
1032  readConstructed( stream, NULL, CTAG_CF_SUBJECT );
1033  status = readSubjectDN( stream, certInfoPtr );
1034  if( cryptStatusError( status ) )
1035  return( status );
1036  }
1037 
1038  /* Read the public key information. CRMF uses yet more nonstandard
1039  tagging for the public key, in theory we'd have to read it with the
1040  CTAG_CF_PUBLICKEY tag instead of the default SEQUENCE, however the
1041  public-key-read code reads the SPKI encapsulation as a generic hole
1042  to handle this so there's no need for any special handling */
1043  if( peekTag( stream ) != MAKE_CTAG( CTAG_CF_PUBLICKEY ) )
1044  {
1045  return( certErrorReturn( certInfoPtr,
1047  CRYPT_ERROR_BADDATA ) );
1048  }
1049  status = readPublicKeyInfo( stream, certInfoPtr );
1050  if( cryptStatusError( status ) )
1051  return( certErrorReturn( certInfoPtr,
1053 
1054  /* Read the attributes */
1055  if( stell( stream ) < endPos - MIN_ATTRIBUTE_SIZE && \
1056  peekTag( stream ) == MAKE_CTAG( CTAG_CF_EXTENSIONS ) )
1057  {
1058  status = readConstructed( stream, &length, CTAG_CF_EXTENSIONS );
1059  if( cryptStatusOK( status ) && length >= MIN_ATTRIBUTE_SIZE )
1060  {
1061  status = readAttributes( stream, &certInfoPtr->attributes,
1063  &certInfoPtr->errorLocus, &certInfoPtr->errorType );
1064  }
1065  if( cryptStatusError( status ) )
1066  return( status );
1067  }
1068 
1069  /* Fix up any problems in attributes */
1070  status = fixAttributes( certInfoPtr );
1071  if( cryptStatusError( status ) )
1072  return( status );
1073 
1074  /* The request may contain additional data that doesn't apply to the
1075  request itself but to the management of the request by CMP (which
1076  means that it should actually be part of the management protocol and
1077  not the request data but CMP muddles things up quite thoroughly,
1078  including encoding CMP protocol data inside fields in the issuer
1079  certificate(!!)). Because we can't do anything with this
1080  information, we just skip it if it's present */
1081  if( stell( stream ) < endPos - MIN_ATTRIBUTE_SIZE )
1082  readUniversal( stream ); /* Skip request management information */
1083 
1084  /* CRMF requests are usually self-signed, however if they've been
1085  generated with an encryption-only key then the place of the signature
1086  is taken by one of a number of magic values which indicate that no
1087  signature is present and that something else needs to be done to
1088  verify that the sender has the private key */
1089  tag = peekTag( stream );
1090  if( cryptStatusError( tag ) )
1091  return( tag );
1092  tag = EXTRACT_CTAG( tag );
1093  if( tag == CTAG_CF_POP_SIGNATURE )
1094  {
1095  /* It's a signature, the request is self-signed */
1096  certInfoPtr->flags |= CERT_FLAG_SELFSIGNED;
1097  }
1098  else
1099  {
1100  /* If it's neither a signature nor an indication that private-key
1101  POP will be performed by returning the certificate in encrypted
1102  form we can't do anything with it */
1103  if( tag != CTAG_CF_POP_ENCRKEY )
1104  return( CRYPT_ERROR_BADDATA );
1105  }
1106  return( readConstructed( stream, NULL, EXTRACT_CTAG( tag ) ) );
1107  }
1108 
1109 /* Read CRMF revocation request information:
1110 
1111  RevDetails ::= SEQUENCE {
1112  certTemplate SEQUENCE {
1113  serialNumber [ 1 ] INTEGER,
1114  issuer [ 3 ] EXPLICIT Name,
1115  },
1116  crlEntryDetails SET OF Attribute
1117  }
1118 
1119  We enforce the requirement that the request must contain at least an
1120  issuer DN and a serial number */
1121 
1122 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1123 static int readRevRequestInfo( INOUT STREAM *stream,
1124  INOUT CERT_INFO *certInfoPtr )
1125  {
1126  int length, endPos, status;
1127 
1128  assert( isWritePtr( stream, sizeof( STREAM ) ) );
1129  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1130 
1131  /* Find out how much certificate template is present */
1132  status = readSequence( stream, &length );
1133  if( cryptStatusError( status ) )
1134  return( status );
1135  endPos = stell( stream ) + length;
1136 
1137  /* Skip any junk before the serial number and read the serial number */
1138  status = skipCrmfJunk( stream, endPos,
1140  NO_TAG, NO_TAG );
1141  if( cryptStatusOK( status ) )
1142  status = readSerialNumber( stream, certInfoPtr,
1144  if( cryptStatusError( status ) )
1145  return( status );
1146 
1147  /* Skip any further junk before the issuer name and read the issuer
1148  name. We don't actually care about the contents of the DN but we
1149  have to decode it anyway in case the caller wants to view it */
1150  status = skipCrmfJunk( stream, endPos, MAKE_CTAG( CTAG_CF_ISSUER ),
1151  NO_TAG, NO_TAG );
1152  if( cryptStatusOK( status ) )
1153  {
1154  readConstructed( stream, NULL, CTAG_CF_ISSUER );
1155  status = readIssuerDN( stream, certInfoPtr );
1156  }
1157  if( cryptStatusError( status ) )
1158  return( status );
1159 
1160  /* Skip any additional junk that may be present in the template,
1161  stopping if we get to the request attributes */
1162  status = skipCrmfJunk( stream, endPos, MAKE_CTAG( CTAG_CF_EXTENSIONS ),
1163  NO_TAG, NO_TAG );
1164  if( cryptStatusError( status ) )
1165  return( status );
1166 
1167  /* Read the attributes */
1168  if( stell( stream ) < endPos - MIN_ATTRIBUTE_SIZE && \
1169  peekTag( stream ) == MAKE_CTAG( CTAG_CF_EXTENSIONS ) )
1170  {
1171  status = readConstructed( stream, &length, CTAG_CF_EXTENSIONS );
1172  if( cryptStatusOK( status ) && length >= MIN_ATTRIBUTE_SIZE )
1173  {
1174  status = readAttributes( stream, &certInfoPtr->attributes,
1176  length, &certInfoPtr->errorLocus,
1177  &certInfoPtr->errorType );
1178  }
1179  if( cryptStatusError( status ) )
1180  return( status );
1181  }
1182 
1183  /* Fix up any problems in attributes */
1184  return( fixAttributes( certInfoPtr ) );
1185  }
1186 #endif /* USE_CERTREQ */
1187 
1188 /****************************************************************************
1189 * *
1190 * Read Validity-checking Objects *
1191 * *
1192 ****************************************************************************/
1193 
1194 #ifdef USE_CERTVAL
1195 
1196 /* Read an RTCS request:
1197 
1198  RTCSRequests ::= SEQUENCE {
1199  SEQUENCE OF SEQUENCE {
1200  certHash OCTET STRING SIZE(20)
1201  },
1202  attributes Attributes OPTIONAL
1203  } */
1204 
1205 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1206 static int readRtcsRequestInfo( INOUT STREAM *stream,
1207  INOUT CERT_INFO *certInfoPtr )
1208  {
1209  CERT_VAL_INFO *certValInfo = certInfoPtr->cCertVal;
1210  int length, endPos, fieldsProcessed, status;
1211 
1212  assert( isWritePtr( stream, sizeof( STREAM ) ) );
1213  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1214 
1215  /* Read the outer wrapper and SEQUENCE OF request information and make
1216  the currently selected one the start of the list */
1217  status = readSequence( stream, &length );
1218  if( cryptStatusError( status ) )
1219  return( status );
1220  endPos = stell( stream ) + length;
1221  status = readSequence( stream, &length );
1222  for( fieldsProcessed = 0;
1223  cryptStatusOK( status ) && length > MIN_ATTRIBUTE_SIZE && \
1224  fieldsProcessed < FAILSAFE_ITERATIONS_LARGE;
1225  fieldsProcessed++ )
1226  {
1227  const int innerStartPos = stell( stream );
1228 
1229  REQUIRES( innerStartPos > 0 && innerStartPos < MAX_INTLENGTH );
1230 
1231  status = readRtcsRequestEntry( stream, &certValInfo->validityInfo,
1232  certInfoPtr );
1233  if( cryptStatusOK( status ) )
1234  length -= stell( stream ) - innerStartPos;
1235  }
1236  if( cryptStatusOK( status ) && \
1237  fieldsProcessed >= FAILSAFE_ITERATIONS_LARGE )
1238  status = CRYPT_ERROR_OVERFLOW;
1239  if( cryptStatusError( status ) )
1240  {
1241  /* The invalid attribute isn't quite a user certificate, but it's the
1242  data that arose from a user certificate so it's the most
1243  appropriate locus for the error */
1244  return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
1245  status ) );
1246  }
1247  certValInfo->currentValidity = certValInfo->validityInfo;
1248 
1249  /* Read the extensions if there are any present. Because some requests
1250  will have broken encoding of lengths we allow for a bit of slop for
1251  software that gets the length encoding wrong by a few bytes */
1252  if( stell( stream ) < endPos - MIN_ATTRIBUTE_SIZE )
1253  {
1254  status = readAttributes( stream, &certInfoPtr->attributes,
1255  CRYPT_CERTTYPE_RTCS_REQUEST, endPos - stell( stream ),
1256  &certInfoPtr->errorLocus, &certInfoPtr->errorType );
1257  if( cryptStatusError( status ) )
1258  return( status );
1259  }
1260 
1261  /* Fix up any problems in attributes */
1262  return( fixAttributes( certInfoPtr ) );
1263  }
1264 
1265 /* Read an RTCS response:
1266 
1267  RTCSResponse ::= SEQUENCE OF SEQUENCE {
1268  certHash OCTET STRING SIZE(20),
1269  RESPONSEINFO
1270  } */
1271 
1272 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1273 static int readRtcsResponseInfo( INOUT STREAM *stream,
1274  INOUT CERT_INFO *certInfoPtr )
1275  {
1276  CERT_VAL_INFO *certValInfo = certInfoPtr->cCertVal;
1277  int length, endPos, fieldsProcessed, status;
1278 
1279  assert( isWritePtr( stream, sizeof( STREAM ) ) );
1280  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1281 
1282  /* Read the SEQUENCE OF validity information and make the currently
1283  selected one the start of the list */
1284  status = readSequence( stream, &length );
1285  if( cryptStatusError( status ) )
1286  return( status );
1287  endPos = stell( stream ) + length;
1288  for( fieldsProcessed = 0;
1289  cryptStatusOK( status ) && length > MIN_ATTRIBUTE_SIZE && \
1290  fieldsProcessed < FAILSAFE_ITERATIONS_LARGE;
1291  fieldsProcessed++ )
1292  {
1293  const int innerStartPos = stell( stream );
1294 
1295  REQUIRES( innerStartPos > 0 && innerStartPos < MAX_INTLENGTH );
1296 
1297  status = readRtcsResponseEntry( stream, &certValInfo->validityInfo,
1298  certInfoPtr, FALSE );
1299  if( cryptStatusOK( status ) )
1300  length -= stell( stream ) - innerStartPos;
1301  }
1302  if( cryptStatusOK( status ) && \
1303  fieldsProcessed >= FAILSAFE_ITERATIONS_LARGE )
1304  status = CRYPT_ERROR_OVERFLOW;
1305  if( cryptStatusError( status ) )
1306  {
1307  /* The invalid attribute isn't quite a user certificate, but it's the
1308  data that arose from a user certificate so it's the most
1309  appropriate locus for the error */
1310  return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
1311  status ) );
1312  }
1313  certValInfo->currentValidity = certValInfo->validityInfo;
1314 
1315  /* Read the extensions if there are any present. Because some requests
1316  will have broken encoding of lengths we allow for a bit of slop for
1317  software that gets the length encoding wrong by a few bytes */
1318  if( stell( stream ) < endPos - MIN_ATTRIBUTE_SIZE )
1319  {
1320  status = readAttributes( stream, &certInfoPtr->attributes,
1321  CRYPT_CERTTYPE_RTCS_RESPONSE, endPos - stell( stream ),
1322  &certInfoPtr->errorLocus, &certInfoPtr->errorType );
1323  if( cryptStatusError( status ) )
1324  return( status );
1325  }
1326 
1327  return( CRYPT_OK );
1328  }
1329 #endif /* USE_CERTVAL */
1330 
1331 /****************************************************************************
1332 * *
1333 * Read Revocation-checking Objects *
1334 * *
1335 ****************************************************************************/
1336 
1337 #ifdef USE_CERTREV
1338 
1339 /* Read an OCSP request:
1340 
1341  OCSPRequest ::= SEQUENCE { -- Write, v1
1342  version [0] EXPLICIT INTEGER DEFAULT(0),
1343  reqName [1] EXPLICIT [4] EXPLICIT DirectoryName OPTIONAL,
1344  reqList SEQUENCE OF SEQUENCE {
1345  SEQUENCE { -- certID
1346  hashAlgo AlgorithmIdentifier,
1347  iNameHash OCTET STRING,
1348  iKeyHash OCTET STRING,
1349  serialNo INTEGER
1350  } }
1351  }
1352 
1353  OCSPRequest ::= SEQUENCE { -- Write, v2
1354  version [0] EXPLICIT INTEGER (1),
1355  reqName [1] EXPLICIT [4] EXPLICIT DirectoryName OPTIONAL,
1356  reqList SEQUENCE OF SEQUENCE {
1357  certID [2] EXPLICIT OCTET STRING -- Certificate hash
1358  }
1359  } */
1360 
1361 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1362 static int readOcspRequestInfo( INOUT STREAM *stream,
1363  INOUT CERT_INFO *certInfoPtr )
1364  {
1365  CERT_REV_INFO *certRevInfo = certInfoPtr->cCertRev;
1366  int length, endPos, fieldsProcessed, status;
1367 
1368  assert( isWritePtr( stream, sizeof( STREAM ) ) );
1369  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1370 
1371  /* Read the wrapper, version information, and requestor name */
1372  status = readSequence( stream, &length );
1373  if( cryptStatusError( status ) )
1374  return( status );
1375  endPos = stell( stream ) + length;
1376  status = readVersion( stream, certInfoPtr, CTAG_OR_VERSION, 1 );
1377  if( cryptStatusError( status ) )
1378  return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_VERSION,
1379  status ) );
1380  if( peekTag( stream ) == MAKE_CTAG( CTAG_OR_DUMMY ) )
1381  readUniversal( stream );
1382 
1383  /* Read the SEQUENCE OF revocation information and make the currently
1384  selected one the start of the list */
1385  status = readSequence( stream, &length );
1386  for( fieldsProcessed = 0;
1387  cryptStatusOK( status ) && length > MIN_ATTRIBUTE_SIZE && \
1388  fieldsProcessed < FAILSAFE_ITERATIONS_LARGE;
1389  fieldsProcessed++ )
1390  {
1391  const int innerStartPos = stell( stream );
1392 
1393  REQUIRES( innerStartPos > 0 && innerStartPos < MAX_INTLENGTH );
1394 
1395  status = readOcspRequestEntry( stream, &certRevInfo->revocations,
1396  certInfoPtr );
1397  if( cryptStatusOK( status ) )
1398  length -= stell( stream ) - innerStartPos;
1399  }
1400  if( cryptStatusOK( status ) && \
1401  fieldsProcessed >= FAILSAFE_ITERATIONS_LARGE )
1402  status = CRYPT_ERROR_OVERFLOW;
1403  if( cryptStatusError( status ) )
1404  {
1405  /* The invalid attribute isn't quite a user certificate, but it's the
1406  data that arose from a user certificate so it's the most
1407  appropriate locus for the error */
1408  return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
1409  status ) );
1410  }
1411  certRevInfo->currentRevocation = certRevInfo->revocations;
1412 
1413  /* Read the extensions if there are any present. Because some requests
1414  will have broken encoding of lengths we allow for a bit of slop for
1415  software that gets the length encoding wrong by a few bytes */
1416  if( stell( stream ) < endPos - MIN_ATTRIBUTE_SIZE )
1417  {
1418  status = readAttributes( stream, &certInfoPtr->attributes,
1419  CRYPT_CERTTYPE_OCSP_REQUEST, endPos - stell( stream ),
1420  &certInfoPtr->errorLocus, &certInfoPtr->errorType );
1421  if( cryptStatusError( status ) )
1422  return( status );
1423  }
1424 
1425  /* Fix up any problems in attributes */
1426  return( fixAttributes( certInfoPtr ) );
1427  }
1428 
1429 /* Read an OCSP response:
1430 
1431  OCSPResponse ::= SEQUENCE {
1432  version [0] EXPLICIT INTEGER DEFAULT (0),
1433  respID [1] EXPLICIT Name,
1434  producedAt GeneralizedTime,
1435  responses SEQUENCE OF Response
1436  exts [1] EXPLICIT Extensions OPTIONAL,
1437  } */
1438 
1439 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1440 static int readOcspResponseInfo( INOUT STREAM *stream,
1441  INOUT CERT_INFO *certInfoPtr )
1442  {
1443  CERT_REV_INFO *certRevInfo = certInfoPtr->cCertRev;
1444  time_t dummyTime;
1445  int length, endPos, fieldsProcessed, status;
1446 
1447  assert( isWritePtr( stream, sizeof( STREAM ) ) );
1448  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1449 
1450  /* Read the wrapper, version information, and responder ID */
1451  status = readSequence( stream, &length );
1452  if( cryptStatusError( status ) )
1453  return( status );
1454  endPos = stell( stream ) + length;
1455  status = readVersion( stream, certInfoPtr, CTAG_OP_VERSION, 1 );
1456  if( cryptStatusError( status ) )
1457  return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_VERSION,
1458  status ) );
1459  if( peekTag( stream ) == MAKE_CTAG( 1 ) )
1460  {
1461  /* It's a DN, read it as the issuer name in case the caller is
1462  interested in it */
1463  readConstructed( stream, NULL, 1 );
1464  status = readIssuerDN( stream, certInfoPtr );
1465  if( cryptStatusError( status ) )
1466  return( status );
1467  }
1468  else
1469  {
1470  /* We can't do much with a key hash, in any case all current
1471  responders use the issuer DN to identify the responder so
1472  this shouldn't be much of a problem */
1473  readUniversal( stream );
1474  }
1475  status = readGeneralizedTime( stream, &dummyTime );
1476  if( cryptStatusError( status ) )
1477  return( status );
1478 
1479  /* Read the SEQUENCE OF revocation information and make the currently
1480  selected one the start of the list */
1481  status = readSequence( stream, &length );
1482  for( fieldsProcessed = 0;
1483  cryptStatusOK( status ) && length > MIN_ATTRIBUTE_SIZE && \
1484  fieldsProcessed < FAILSAFE_ITERATIONS_LARGE;
1485  fieldsProcessed++ )
1486  {
1487  const int innerStartPos = stell( stream );
1488 
1489  REQUIRES( innerStartPos > 0 && innerStartPos < MAX_INTLENGTH );
1490 
1491  status = readOcspResponseEntry( stream, &certRevInfo->revocations,
1492  certInfoPtr );
1493  if( cryptStatusOK( status ) )
1494  length -= stell( stream ) - innerStartPos;
1495  }
1496  if( cryptStatusOK( status ) && \
1497  fieldsProcessed >= FAILSAFE_ITERATIONS_LARGE )
1498  status = CRYPT_ERROR_OVERFLOW;
1499  if( cryptStatusError( status ) )
1500  {
1501  /* The invalid attribute isn't quite a user certificate, but it's the
1502  data that arose from a user certificate so it's the most
1503  appropriate locus for the error */
1504  return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
1505  status ) );
1506  }
1507  certRevInfo->currentRevocation = certRevInfo->revocations;
1508 
1509  /* Read the extensions if there are any present */
1510  if( stell( stream ) < endPos - MIN_ATTRIBUTE_SIZE )
1511  {
1512  status = readAttributes( stream, &certInfoPtr->attributes,
1513  CRYPT_CERTTYPE_OCSP_RESPONSE, endPos - stell( stream ),
1514  &certInfoPtr->errorLocus, &certInfoPtr->errorType );
1515  }
1516 
1517  /* In theory some OCSP responses can be sort of self-signed via attached
1518  certificates but there are so many incompatible ways to delegate
1519  trust and signing authority mentioned in the RFC (one for each vendor
1520  that contributed and an additional catchall in case any option got
1521  missed) without any indication of which one implementors will follow
1522  that we require the user to supply the signature check certificate
1523  rather than assuming that some particular trust delegation mechanism
1524  will happen to be in place */
1525 /* certInfoPtr->flags |= CERT_FLAG_SELFSIGNED; */
1526  return( status );
1527  }
1528 #endif /* USE_CERTREV */
1529 
1530 /****************************************************************************
1531 * *
1532 * Read CMS Attribute Objects *
1533 * *
1534 ****************************************************************************/
1535 
1536 #ifdef USE_CMSATTR
1537 
1538 /* Read CMS attributes */
1539 
1540 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1541 static int readCmsAttributes( INOUT STREAM *stream,
1542  INOUT CERT_INFO *attributeInfoPtr )
1543  {
1544  assert( isWritePtr( stream, sizeof( STREAM ) ) );
1545  assert( isWritePtr( attributeInfoPtr, sizeof( CERT_INFO ) ) );
1546 
1547  /* CMS attributes are straight attribute objects so we just pass the call
1548  through. In addition since there's no encapsulation we specify a
1549  special-case length of 0 to mean "whatever's there" */
1550  return( readAttributes( stream, &attributeInfoPtr->attributes,
1552  &attributeInfoPtr->errorLocus,
1553  &attributeInfoPtr->errorType ) );
1554  }
1555 #endif /* USE_CMSATTR */
1556 
1557 /****************************************************************************
1558 * *
1559 * Read PKI User Objects *
1560 * *
1561 ****************************************************************************/
1562 
1563 #ifdef USE_PKIUSER
1564 
1565 /* Read PKI user information:
1566 
1567  userData ::= SEQUENCE {
1568  name Name, -- Name for CMP
1569  encAlgo AlgorithmIdentifier,-- Algo to encrypt passwords
1570  encPW OCTET STRING, -- Encrypted passwords
1571  attributes Attributes
1572  } */
1573 
1574 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1575 static int readPkiUserInfo( INOUT STREAM *stream,
1576  INOUT CERT_INFO *userInfoPtr )
1577  {
1579  CERT_PKIUSER_INFO *certUserInfo = userInfoPtr->cCertUser;
1580  MESSAGE_CREATEOBJECT_INFO createInfo;
1581  ATTRIBUTE_PTR *attributeCursor;
1584  STREAM userInfoStream;
1585  ATTRIBUTE_ENUM_INFO attrEnumInfo;
1586  BYTE userInfo[ 128 + 8 ];
1587  int userInfoSize = DUMMY_INIT, length, iterationCount, status;
1588 
1589  assert( isWritePtr( stream, sizeof( STREAM ) ) );
1590  assert( isWritePtr( userInfoPtr, sizeof( CERT_INFO ) ) );
1591 
1592  /* Read the user name, encryption algorithm information, and the start
1593  of the encrypted data */
1594  status = getStreamObjectLength( stream, &length );
1595  if( cryptStatusOK( status ) )
1596  {
1597  userInfoPtr->subjectDNsize = length;
1598  status = sMemGetDataBlock( stream, &userInfoPtr->subjectDNptr,
1599  length );
1600  }
1601  if( cryptStatusOK( status ) )
1602  status = readDN( stream, &userInfoPtr->subjectName );
1603  if( cryptStatusError( status ) )
1604  return( status );
1605  status = readContextAlgoID( stream, NULL, &queryInfo, DEFAULT_TAG,
1607  if( cryptStatusOK( status ) )
1608  status = readOctetString( stream, userInfo, &userInfoSize, 8, 128 );
1609  if( cryptStatusError( status ) )
1610  return( status );
1611  if( userInfoSize != PKIUSER_ENCR_AUTHENTICATOR_SIZE )
1612  return( CRYPT_ERROR_BADDATA );
1613 
1614  /* Clone the CA data storage key for our own use, load the IV from the
1615  encryption information, and use the cloned context to decrypt the
1616  user information. We need to do this to prevent problems if multiple
1617  threads try to simultaneously decrypt with the CA data storage key.
1618  See the comment in write.c for the use of the fixed interop key
1619  rather than actually using a clone of the CA data storage key as the
1620  comment would imply */
1621  setMessageCreateObjectInfo( &createInfo, queryInfo.cryptAlgo );
1623  &createInfo, OBJECT_TYPE_CONTEXT );
1624  if( cryptStatusError( status ) )
1625  return( status );
1626  iCryptContext = createInfo.cryptHandle;
1627  setMessageData( &msgData, "interop interop interop ", 24 );
1628  status = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE_S,
1629  &msgData, CRYPT_CTXINFO_KEY );
1630  if( cryptStatusOK( status ) )
1631  {
1632  setMessageData( &msgData, queryInfo.iv, queryInfo.ivLength );
1633  krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE_S, &msgData,
1634  CRYPT_CTXINFO_IV );
1635  status = krnlSendMessage( iCryptContext, IMESSAGE_CTX_DECRYPT,
1636  userInfo, userInfoSize );
1637  }
1638  krnlSendNotifier( iCryptContext, IMESSAGE_DECREFCOUNT );
1639  if( cryptStatusError( status ) )
1640  return( status );
1641 
1642  /* Read the user information. If we get a bad data error at this point
1643  we report it as a wrong decryption key rather than bad data since
1644  it's more likely to be the former */
1645  sMemConnect( &userInfoStream, userInfo, userInfoSize );
1646  readSequence( &userInfoStream, NULL );
1647  readOctetString( &userInfoStream, certUserInfo->pkiIssuePW, &length,
1649  status = readOctetString( &userInfoStream, certUserInfo->pkiRevPW,
1650  &length, PKIUSER_AUTHENTICATOR_SIZE,
1652  sMemDisconnect( &userInfoStream );
1653  zeroise( userInfo, userInfoSize );
1654  if( cryptStatusError( status ) )
1655  return( CRYPT_ERROR_WRONGKEY );
1656 
1657  /* Read the user ID and any other attributes */
1658  status = readAttributes( stream, &userInfoPtr->attributes,
1659  CRYPT_CERTTYPE_PKIUSER, sMemDataLeft( stream ),
1660  &userInfoPtr->errorLocus,
1661  &userInfoPtr->errorType );
1662  if( cryptStatusError( status ) )
1663  return( status );
1664 
1665  /* As used by cryptlib the PKI user information is applied as a template
1666  to certificates to modify their contents before issue. This is done
1667  by merging the user information with the certificate before it's
1668  issued. Since there can be overlapping or conflicting attributes in
1669  the two objects, the ones in the PKI user information are marked as
1670  locked to ensure that they override any conflicting attributes that
1671  may be present in the certificate */
1672  for( attributeCursor = ( ATTRIBUTE_PTR * ) \
1673  getFirstAttribute( &attrEnumInfo,
1674  userInfoPtr->attributes,
1676  iterationCount = 0;
1677  attributeCursor != NULL && \
1678  iterationCount < FAILSAFE_ITERATIONS_MAX;
1679  attributeCursor = ( ATTRIBUTE_PTR * ) \
1680  getNextAttribute( &attrEnumInfo ), \
1681  iterationCount++ )
1682  {
1683  setAttributeProperty( attributeCursor,
1685  }
1686  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MAX );
1687 
1688  return( CRYPT_OK );
1689  }
1690 #endif /* USE_PKIUSER */
1691 
1692 /****************************************************************************
1693 * *
1694 * Read Function Access Information *
1695 * *
1696 ****************************************************************************/
1697 
1698 typedef struct {
1699  const CRYPT_CERTTYPE_TYPE type;
1700  const READCERT_FUNCTION function;
1701  } CERTREAD_INFO;
1702 static const CERTREAD_INFO FAR_BSS certReadTable[] = {
1703  { CRYPT_CERTTYPE_CERTIFICATE, readCertInfo },
1704  { CRYPT_CERTTYPE_ATTRIBUTE_CERT, readAttributeCertInfo },
1705 #ifdef USE_CERTREV
1706  { CRYPT_CERTTYPE_CRL, readCRLInfo },
1707 #endif /* USE_CERTREV */
1708 #ifdef USE_CERTREQ
1709  { CRYPT_CERTTYPE_CERTREQUEST, readCertRequestInfo },
1710  { CRYPT_CERTTYPE_REQUEST_CERT, readCrmfRequestInfo },
1711  { CRYPT_CERTTYPE_REQUEST_REVOCATION, readRevRequestInfo },
1712 #endif /* USE_CERTREQ */
1713 #ifdef USE_CERTVAL
1714  { CRYPT_CERTTYPE_RTCS_REQUEST, readRtcsRequestInfo },
1715  { CRYPT_CERTTYPE_RTCS_RESPONSE, readRtcsResponseInfo },
1716 #endif /* USE_CERTVAL */
1717 #ifdef USE_CERTREV
1718  { CRYPT_CERTTYPE_OCSP_REQUEST, readOcspRequestInfo },
1719  { CRYPT_CERTTYPE_OCSP_RESPONSE, readOcspResponseInfo },
1720 #endif /* USE_CERTREV */
1721 #ifdef USE_CMSATTR
1722  { CRYPT_CERTTYPE_CMS_ATTRIBUTES, readCmsAttributes },
1723 #endif /* USE_CMSATTR */
1724 #ifdef USE_PKIUSER
1725  { CRYPT_CERTTYPE_PKIUSER, readPkiUserInfo },
1726 #endif /* USE_PKIUSER */
1727  { CRYPT_CERTTYPE_NONE, NULL }, { CRYPT_CERTTYPE_NONE, NULL }
1728  };
1729 
1730 CHECK_RETVAL_PTR \
1731 READCERT_FUNCTION getCertReadFunction( IN_ENUM( CRYPT_CERTTYPE ) \
1733  {
1734  int i;
1735 
1736  REQUIRES_N( certType > CRYPT_CERTTYPE_NONE && certType < CRYPT_CERTTYPE_LAST );
1737 
1738  for( i = 0;
1739  certReadTable[ i ].type != CRYPT_CERTTYPE_NONE && \
1740  i < FAILSAFE_ARRAYSIZE( certReadTable, CERTREAD_INFO );
1741  i++ )
1742  {
1743  if( certReadTable[ i ].type == certType )
1744  return( certReadTable[ i ].function );
1745  }
1746  ENSURES_N( i < FAILSAFE_ARRAYSIZE( certReadTable, CERTREAD_INFO ) );
1747 
1748  return( NULL );
1749  }
1750 #endif /* USE_CERTIFICATES */