cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
imp_chk.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Certificate Import Format-check Routines *
4 * Copyright Peter Gutmann 1997-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 /* Oddball OIDs that may be used to wrap certificates */
19 
20 #define OID_X509_USERCERTIFICATE MKOID( "\x06\x03\x55\x04\x24" )
21 
22 /* If fed an unknown object from the external source we can (with some
23  difficulty) determine its type at runtime (although it's hardly LL(1))
24  and import it as appropriate. If fed an object by a cryptlib-internal
25  function, the exact type will always be known.
26 
27  If the data starts with a [0] it's CMS attributes. If it starts with a
28  sequence followed by an OID it's a certificate chain/sequence or (rarely)
29  a certificate wrapped up in some weird packaging. If it starts with a
30  sequence followed by an integer (version = 3) it's a PKCS #12 mess.
31  Otherwise it follows the general pattern SEQUENCE { tbsSomething,
32  signature }, and it's at this point that distinguishing the different
33  types gets tricky, with the following top-level formats being possible:
34 
35  Cert: SEQUENCE { SEQUENCE {
36  [0] EXPLICIT ... OPTIONAL,
37  INTEGER,
38  AlgorithmID,
39  Name,
40  SEQUENCE { -- Validity
41  UTCTime | GeneralizedTime
42 
43  Attribute cert: SEQUENCE { SEQUENCE {
44  INTEGER,
45  SEQUENCE {
46  [1] Name,
47  ...
48  }
49 
50  CRL: SEQUENCE { SEQUENCE {
51  INTEGER OPTIONAL,
52  AlgorithmID,
53  Name,
54  UTCTime | GeneralizedTime
55 
56  Cert request: SEQUENCE { SEQUENCE {
57  INTEGER,
58  Name,
59  SEQUENCE { -- SubjectPublicKeyInfo
60  AlgorithmID
61 
62  CRMF request: SEQUENCE { SEQUENCE {
63  INTEGER,
64  SEQUENCE {
65  [0] ... [9] -- cert request should have
66  -- [6] SubjectPublicKeyInfo
67 
68  CRMF rev.req: SEQUENCE { SEQUENCE {
69  [0] ... [9] -- Should have [1] INTEGER
70  -- (= serialNo)
71 
72  OCSP request: SEQUENCE { SEQUENCE {
73  [0] EXPLICIT ... OPTIONAL,
74  [1] EXPLICIT ... OPTIONAL,
75  SEQUENCE { SEQUENCE {
76  SEQUENCE ... -- For certID, abandoned v2 also
77  -- allowed [0] | [1] | [2] | [3]
78  -- for other IDs.
79 
80  OCSP resp: SEQUENCE { SEQUENCE {
81  [0] EXPLICIT ... OPTIONAL,
82  [1] | [2] ..., -- responderID = CHOICE [1] | [2]
83  GeneralizedTime
84 
85  RTCS request: SEQUENCE { SEQUENCE {
86  SEQUENCE {
87  OCTET STRING -- certHash
88 
89  RTCS resp: SEQUENCE { SEQUENCE
90  OCTET STRING -- certHash
91 
92  PKI user: SEQUENCE { SEQUENCE { -- Name
93  SET ... | empty -- RDN or zero-length DN
94 
95  The first step is to strip out the SEQUENCE { SEQUENCE, which is shared
96  by all objects. In addition we can remove the [0] ... OPTIONAL and
97  [1] ... OPTIONAL, which isn't useful in distinguishing anything. Since
98  the standard OCSP response can also have [2] in place of the [1] and
99  leaving it in isn't notably useful we strip this as well. Note that PKI
100  user information can be left in one of two states depending on whether
101  there's a DN present. Rather than parse down into the rest of the PKI
102  user object (the next element is an AlgorithmID that clashes with a
103  certificate and CRL) we use the presence of a zero-length sequence to
104  identify a PKI user object with an absent DN. This leaves the following:
105 
106  Cert: INTEGER,
107  AlgorithmID,
108  Name,
109  SEQUENCE { -- Validity
110  UTCTime | GeneralizedTime
111 
112  Attribute cert: INTEGER,
113  SEQUENCE {
114  [1] Name,
115  ...
116  }
117 
118  CRL: INTEGER OPTIONAL,
119  AlgorithmID,
120  Name,
121  UTCTime | GeneralizedTime
122 
123  Cert request: INTEGER,
124  Name,
125  SEQUENCE { -- SubjectPublicKeyInfo
126  AlgorithmID
127 
128  CRMF request: INTEGER,
129  SEQUENCE {
130  [0] | [1] | - -- Implicitly tagged
131  [3] ... [9] -- [2] stripped
132 
133  CRMF rev.req: [0] | [1] | - -- Implicitly tagged
134  [3] ... [9] -- [2] stripped
135 
136  OCSP request: SEQUENCE { SEQUENCE {
137  SEQUENCE ... -- [0] | [1] | [2] | [3]
138  -- for other IDs
139 
140  OCSP resp: GeneralizedTime
141 
142  RTCS request: SEQUENCE {
143  OCTET STRING -- certHash
144 
145  RTCS resp: OCTET STRING -- certHash
146 
147  PKI user: SET ... -- RDN
148 
149  Next we have the INTEGER, which also isn't notably useful. Stripping this
150  leaves:
151 
152  Cert: AlgorithmID,
153  Name,
154  SEQUENCE { -- Validity
155  UTCTime | GeneralizedTime
156 
157  Attribute cert: SEQUENCE {
158  [1] Name, -- Constructed tag
159  ...
160  }
161 
162  CRL: AlgorithmID,
163  Name,
164  UTCTime | GeneralizedTime
165 
166  Cert request: Name,
167  SEQUENCE { -- SubjectPublicKeyInfo
168  AlgorithmID
169 
170  CRMF request: SEQUENCE {
171  [0] | [1] | - -- Primitive tag
172  [3] ... [9] -- [2] stripped
173 
174  CRMF rev.req: [0] | [1] | - -- Primitive tag
175  [3] ... [9] -- [2] stripped
176 
177  OCSP request: SEQUENCE { SEQUENCE {
178  SEQUENCE ... -- [0] | [1] | [2] | [3]
179  -- for other IDs
180 
181  OCSP resp: GeneralizedTime
182 
183  RTCS request: SEQUENCE {
184  OCTET STRING -- certHash
185 
186  RTCS resp: OCTET STRING -- certHash
187 
188  PKI user: SET ... -- RDN
189 
190  We can now immediately identify the attribute certificate by the [1] ...
191  constructed tag, a CRMF revocation request by the not-stripped [0] or [1]
192  primitive tags (implicitly tagged INTEGER) or [3]...[9] ..., an OCSP
193  response by the GeneralizedTime, an RTCS response by the OCTET STRING,
194  and the alternative PKI user variant by the SET ..., leaving:
195 
196  Cert: AlgorithmID,
197  Name,
198  SEQUENCE { -- Validity
199  UTCTime | GeneralizedTime
200 
201  CRL: AlgorithmID,
202  Name,
203  UTCTime | GeneralizedTime
204 
205  Cert request: Name,
206  SEQUENCE { -- SubjectPublicKeyInfo
207  AlgorithmID
208 
209  CRMF request: SEQUENCE {
210  [3] ... [9]
211 
212  OCSP request: SEQUENCE { SEQUENCE {
213  SEQUENCE ... -- [0] | [1] | [2] | [3]
214  -- for other IDs
215 
216  RTCS request: SEQUENCE {
217  OCTET STRING -- certHash
218 
219 
220  Expanding the complex types for certificate, CRL, and certificate
221  request, we get:
222 
223  Cert: SEQUENCE { -- AlgorithmID
224  OBJECT IDENTIFIER,
225  ...
226  Name,
227  SEQUENCE { -- Validity
228  UTCTime | GeneralizedTime
229 
230  CRL: SEQUENCE { -- AlgorithmID
231  OBJECT IDENTIFIER,
232  ...
233  Name,
234  UTCTime | GeneralizedTime
235 
236  Cert request: SEQUENCE { -- Name
237  SET {
238  ...
239  ...
240  SEQUENCE { -- SubjectPublicKeyInfo
241  AlgorithmID
242 
243  CRMF request: SEQUENCE {
244  [3] ... [9]
245 
246  OCSP request: SEQUENCE { SEQUENCE {
247  SEQUENCE ... -- [0] | [1] | [2] | [3]
248  -- for other IDs
249 
250  RTCS request: SEQUENCE {
251  OCTET STRING -- certHash
252 
253  Stripping the first SEQUENCE { we get:
254 
255  Cert: OBJECT IDENTIFIER,
256  ...
257  Name,
258  SEQUENCE { -- Validity
259  UTCTime | GeneralizedTime
260 
261  CRL: OBJECT IDENTIFIER,
262  ...
263  Name,
264  UTCTime | GeneralizedTime
265 
266  Cert request: SET {
267  ...
268  ...
269  SEQUENCE { -- SubjectPublicKeyInfo
270  AlgorithmID
271 
272  CRMF request: [3] ... [9]
273 
274  OCSP request: SEQUENCE {
275  SEQUENCE ... -- [0] | [1] | [2] | [3]
276  -- for other IDs
277 
278  RTCS request: OCTET STRING -- certHash
279 
280  which allows us to distinguish certificates and CRLs (the two are
281  themselves distinguished by what follows the second Name), certificate
282  requests, and RTCS requests. What's left now are the tricky ones, the
283  other request and response types:
284 
285  CRMF request: [3] ... [9]
286 
287  OCSP request: SEQUENCE {
288  SEQUENCE ... -- [0] | [1] | [2] | [3]
289  -- for other IDs
290 
291  which can themselves be distinguished by the remaining data.
292 
293  Note that in practice we don't try and auto-recognise all of these
294  because some of them should never be fed to us by a user, for example a
295  CRMF revocation request and PKIUser object is only valid in the context
296  of a CMP transaction and RTCS and OCSP objects are only valid in the
297  contxt of RTCS or OCSP transactions, however we make an exception for
298  CRMF certification requests and OCSP responses because they're used in
299  the self-test */
300 
301 #ifdef USE_CERTIFICATES
302 
303 /****************************************************************************
304 * *
305 * Format Check Routines *
306 * *
307 ****************************************************************************/
308 
309 /* Process any additional wrapper that may surround the certificate */
310 
311 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
312 static int decodeCertWrapper( INOUT STREAM *stream,
313  OUT_ENUM_OPT( CRYPT_CERTTYPE ) \
316  {
317  BYTE oid[ MAX_OID_SIZE + 8 ];
318  long integer;
319  int oidLength, innerLength, value, status;
320 
321  assert( isWritePtr( stream, sizeof( STREAM ) ) );
322  assert( isWritePtr( offset, sizeof( int ) ) );
323 
324  /* Clear return values */
325  *objectType = CRYPT_CERTTYPE_NONE;
326  *offset = 0;
327 
328  /* Read the contentType OID, determine the content type based on it,
329  and read the content encapsulation and header. It can be either
330  a PKCS #7 certificate chain, a Netscape certificate sequence, or an
331  X.509 userCertificate (which is just an oddball certificate
332  wrapper) */
333  status = readEncodedOID( stream, oid, MAX_OID_SIZE, &oidLength,
335  if( cryptStatusError( status ) )
336  return( status );
337 #if 0 /* 21/10/08 Long-obsolete formats, we shouldn't be seeing these any
338  more */
339  if( !memcmp( oid, OID_X509_USERCERTIFICATE, oidLength ) )
340  {
341  /* Oddball wrapper type, set the payload offset to point to the
342  certificate and indicate no wrapper present */
343  *objectType = CRYPT_CERTTYPE_CERTIFICATE;
344  *offset = stell( stream );
345  return( readSequence( stream, NULL ) );
346  }
347  if( !memcmp( oid, OID_NS_CERTSEQ, oidLength ) )
348  {
349  /* Netscape certificate sequence, skip the wrapper and exit */
350  *objectType = CRYPT_CERTTYPE_CERTCHAIN;
351  readConstructedI( stream, NULL, 0 );
352  readSequenceI( stream, NULL );
353  return( readSequence( stream, NULL ) );
354  }
355 #endif /* 0 */
356  if( oidLength != sizeofOID( OID_CMS_SIGNEDDATA ) || \
357  memcmp( oid, OID_CMS_SIGNEDDATA, oidLength ) )
358  return( CRYPT_ERROR_BADDATA );
359  readConstructedI( stream, NULL, 0 );
360  status = readSequenceI( stream, NULL );
361  if( cryptStatusError( status ) )
362  return( status );
363 
364  /* Read the version number (1 = PKCS #7 v1.5, 2 = PKCS #7 v1.6, 3 =
365  S/MIME with attribute certificate(s)) and SET OF
366  DigestAlgorithmIdentifier (this is empty for a pure certificate chain,
367  nonempty for signed data) */
368  status = readShortInteger( stream, &integer );
369  if( cryptStatusError( status ) )
370  return( status );
371  if( integer < 1 || integer > 3 )
372  return( CRYPT_ERROR_BADDATA );
373  status = readSet( stream, &value );
374  if( cryptStatusOK( status ) && value > 0 )
375  status = sSkip( stream, value );
376  if( cryptStatusError( status ) )
377  return( status );
378 
379  /* Read the ContentInfo header, contentType OID (ignored) and the inner
380  content encapsulation. Sometimes we may (incorrectly) get passed
381  actual signed data rather than degenerate zero-length data signifying
382  a pure certificate chain so if there's data present we skip it */
383  readSequenceI( stream, &innerLength );
384  status = readEncodedOID( stream, oid, MAX_OID_SIZE, &oidLength,
386  if( cryptStatusError( status ) )
387  return( status );
388  if( innerLength == CRYPT_UNUSED )
389  {
390  /* It's an indefinite-length ContentInfo, check for the EOC */
391  checkEOC( stream );
392  }
393  else
394  {
395  /* If we've been fed signed data (i.e. the ContentInfo has the
396  content field present), skip the content to get to the
397  certificate chain */
398  if( innerLength > sizeofObject( oidLength ) )
399  readUniversal( stream );
400  }
401  status = readConstructedI( stream, NULL, 0 );
402  if( cryptStatusError( status ) )
403  return( status );
404 
405  /* We've finally reached the certificate(s), retry the read of the
406  certificate start */
407  *objectType = CRYPT_CERTTYPE_CERTCHAIN;
408  return( readSequence( stream, NULL ) );
409  }
410 
411 /* Determine the object type and how long the total object is */
412 
413 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 4 ) ) \
414 int getCertObjectInfo( INOUT STREAM *stream,
417  OUT_ENUM_OPT( CRYPT_CERTTYPE ) \
419  IN_ENUM( CRYPT_CERTTYPE ) \
420  const CRYPT_CERTTYPE_TYPE formatHint )
421  {
422  BOOLEAN isContextTagged = FALSE, isLongData = FALSE;
423  int tag, length, status;
424 
425  assert( isWritePtr( stream, sizeof( STREAM ) ) );
426  assert( isWritePtr( objectOffset, sizeof( int ) ) );
427  assert( isWritePtr( objectLength, sizeof( int ) ) );
428  assert( isWritePtr( objectType, sizeof( CRYPT_CERTTYPE_TYPE ) ) );
429 
430  REQUIRES( formatHint >= CRYPT_CERTTYPE_NONE && \
431  formatHint < CRYPT_CERTTYPE_LAST );
432 
433  /* Clear return values */
434  *objectOffset = *objectLength = 0;
435  *objectType = CRYPT_CERTTYPE_NONE;
436 
437  /* If it's an SSL certificate chain then there's no recognisable
438  tagging, however the caller will have told us what it is */
439  if( formatHint == CRYPT_ICERTTYPE_SSL_CERTCHAIN )
440  {
441  *objectLength = sMemDataLeft( stream );
442  *objectType = CRYPT_ICERTTYPE_SSL_CERTCHAIN;
443  return( CRYPT_OK );
444  }
445 
446  /* Get the object's length */
447  status = getStreamObjectLength( stream, &length );
448  if( cryptStatusError( status ) )
449  {
450 #if INT_MAX > 32767
451  long longLength;
452 
453  if( status != CRYPT_ERROR_OVERFLOW )
454  return( status );
455 
456  /* CRLs can grow without bounds as more and more certificates are
457  accumulated, to handle these we have to fall back to an
458  unconstrained length read if a standard constrained length read
459  fails. We also remember the fact that it's an exceptionally long
460  object and only allow this length if we (eventually) detect that
461  it's associated with a CRL, for anything else we return later
462  with a CRYPT_ERROR_OVERFLOW */
463  sClearError( stream );
464  sseek( stream, 0 );
465  status = getLongStreamObjectLength( stream, &longLength );
466  if( cryptStatusError( status ) )
467  return( status );
468  length = ( int ) longLength;
469  isLongData = TRUE;
470 #else
471  /* Mega-CRLs are too much for 16-bit systems */
472  return( status );
473 #endif /* 16- vs. 32/64-bit systems */
474  }
475  if( length < 16 || length > MAX_INTLENGTH )
476  return( CRYPT_ERROR_BADDATA );
477  *objectLength = length;
478 
479  /* Check that the start of the object is in order */
480  if( peekTag( stream ) == MAKE_CTAG( 0 ) || \
481  formatHint == CRYPT_ICERTTYPE_CMS_CERTSET )
482  isContextTagged = TRUE;
483  status = readConstructedI( stream, &length, \
484  isContextTagged ? 0 : DEFAULT_TAG );
485  if( cryptStatusError( status ) )
486  return( status );
487 
488  /* If the caller has specified that the data is in a fixed format, don't
489  try and recognise any other format. This prevents security holes of
490  the type common in Windows software where data purportedly of type A
491  is auto-recognised as harmful type B and processed as such after being
492  passed as type A by security-checking code */
493  if( formatHint != CRYPT_CERTTYPE_NONE )
494  {
495  switch( formatHint )
496  {
497  case CRYPT_ICERTTYPE_DATAONLY:
498  /* Standard certificate but created without creating a
499  context for the accompanying public key */
500  *objectType = CRYPT_CERTTYPE_CERTIFICATE;
501  break;
502 
503  case CRYPT_ICERTTYPE_CTL:
504  /* Certificate chain used as a container for trusted
505  certificates, effectively a chain of
506  CRYPT_ICERTTYPE_DATAONLY certificates */
507  *objectType = CRYPT_CERTTYPE_CERTCHAIN;
508  break;
509 
510  case CRYPT_ICERTTYPE_REVINFO:
511  /* Single CRL entry, treated as standard CRL with portions
512  missing */
513  *objectType = CRYPT_CERTTYPE_CRL;
514  break;
515 
516  default:
517  *objectType = formatHint;
518  }
519 
520  return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
521  }
522 
523  /* First we check for the easy ones, CMS attributes, which begin with a
524  [0] IMPLICIT SET */
525  if( isContextTagged )
526  {
527  *objectType = CRYPT_CERTTYPE_CMS_ATTRIBUTES;
528  return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
529  }
530 
531  /* If it's a PKCS #7 certificate chain there'll be an object identifier
532  present, check the wrapper */
533  if( peekTag( stream ) == BER_OBJECT_IDENTIFIER )
534  {
535  status = decodeCertWrapper( stream, objectType, objectOffset );
536  if( cryptStatusError( status ) )
537  return( status );
538  return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
539  }
540 
541  /* If it's a PKCS #12 mess there'll be a version number, 3, present */
542  if( peekTag( stream ) == BER_INTEGER )
543  {
544  long value;
545  int offset;
546 
547  /* Strip off the amazing number of layers of bloat that PKCS #12
548  lards a certificate with. There are any number of different
549  interpretations of how to store certificates in a PKCS #12 file,
550  the following is the one that (eventually) ends up in a
551  certificate that we can read */
552  status = readShortInteger( stream, &value );
553  if( cryptStatusError( status ) )
554  return( status );
555  if( value != 3 )
556  return( CRYPT_ERROR_BADDATA );
557  readSequence( stream, NULL );
558  readFixedOID( stream, OID_CMS_DATA, sizeofOID( OID_CMS_DATA ) );
559  readConstructed( stream, NULL, 0 );
560  readOctetStringHole( stream, NULL, 8, DEFAULT_TAG );
561  readSequence( stream, NULL );
562  readSequence( stream, NULL );
563  readFixedOID( stream, OID_CMS_DATA, sizeofOID( OID_CMS_DATA ) );
564  readConstructed( stream, NULL, 0 );
565  readOctetStringHole( stream, NULL, 8, DEFAULT_TAG );
566  readSequence( stream, NULL );
567  readSequence( stream, NULL );
568  readFixedOID( stream,
569  MKOID( "\x06\x0B\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x0A\x01\x03" ),
570  13 );
571  readConstructed( stream, NULL, 0 );
572  readSequence( stream, NULL );
573  readFixedOID( stream,
574  MKOID( "\x06\x0A\x2A\x86\x48\x86\xF7\x0D\x01\x09\x16\x01" ),
575  12 );
576  readConstructed( stream, NULL, 0 );
577  status = readOctetStringHole( stream, &length, 8, DEFAULT_TAG );
578  if( cryptStatusError( status ) )
579  return( status );
580  offset = stell( stream ); /* Certificate start */
581  readSequence( stream, NULL );
582  status = readSequence( stream, NULL );
583  if( cryptStatusError( status ) )
584  return( status );
585 
586  /* We've finally reached the certificate, record its offset and
587  length */
588  *objectOffset = offset;
589  *objectLength = length;
590  *objectType = CRYPT_CERTTYPE_CERTIFICATE;
591  return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
592  }
593 
594  /* Read the inner sequence */
595  if( isLongData )
596  {
597  long longLength;
598 
599  status = readLongSequence( stream, &longLength );
600  if( cryptStatusOK( status ) )
601  {
602  /* If it's an (invalid) indefinite-length encoding we can't do
603  anything with it */
604  if( longLength == CRYPT_UNUSED )
605  status = CRYPT_ERROR_BADDATA;
606  else
607  length = ( int ) longLength;
608  }
609  }
610  else
611  status = readSequence( stream, &length );
612  if( cryptStatusError( status ) )
613  return( status );
614 
615  /* Skip optional tagged fields and the INTEGER value */
616  if( peekTag( stream ) == MAKE_CTAG( 0 ) )
617  status = readUniversal( stream );
618  if( peekTag( stream ) == MAKE_CTAG( 1 ) )
619  status = readUniversal( stream );
620  if( peekTag( stream ) == MAKE_CTAG( 2 ) )
621  status = readUniversal( stream );
622  if( peekTag( stream ) == BER_INTEGER )
623  status = readUniversal( stream );
624  if( cryptStatusError( status ) )
625  return( status );
626 #if 0 /* 21/10/08 Disabled, see comment at start */
627  if( length <= 0 )
628  {
629  /* PKI user object with absent (non-specified) DN */
630  *objectType = CRYPT_CERTTYPE_PKIUSER;
631  return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
632  }
633 #endif /* 0 */
634 
635  /* If we've hit a GeneralizedTime it's an OCSP response, if we've hit
636  a SET it's PKI user information, and if we've hit a [0] or [1]
637  primitive tag (implicitly tagged INTEGER) or [3]...[9] it's a CRMF
638  revocation request */
639  tag = peekTag( stream );
640  if( cryptStatusError( tag ) )
641  return( tag );
642  if( tag == BER_TIME_GENERALIZED )
643  {
644  *objectType = CRYPT_CERTTYPE_OCSP_RESPONSE;
645  return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
646  }
647 #if 0 /* 21/10/08 Disabled, see comment at start */
648  if( tag == BER_OCTETSTRING )
649  {
650  *objectType = CRYPT_CERTTYPE_RTCS_RESPONSE;
651  return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
652  }
653  if( tag == BER_SET )
654  {
655  *objectType = CRYPT_CERTTYPE_PKIUSER;
656  return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
657  }
658  if( tag == MAKE_CTAG_PRIMITIVE( 0 ) || \
659  tag == MAKE_CTAG_PRIMITIVE( 1 ) || \
660  ( tag >= MAKE_CTAG( 3 ) && tag <= MAKE_CTAG( 9 ) ) )
661  {
662  *objectType = CRYPT_CERTTYPE_REQUEST_REVOCATION;
663  return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
664  }
665 #endif /* 0 */
666 
667  /* Read the next SEQUENCE. If it's followed by an OID it's the
668  AlgorithmIdentifier in a certificate or CRL, if it's followed by a
669  SET it's the Name in a certificate request, if it's followed by a
670  [1] constructed tag it's an attribute certificate, and if it's
671  followed by a tag in the range [0]...[9] it's a horror from CRMF */
672  status = readSequence( stream, &length );
673  if( cryptStatusError( status ) )
674  return( status );
675  if( length <= 0 || length > MAX_INTLENGTH )
676  return( CRYPT_ERROR_BADDATA );
677  tag = peekTag( stream );
678  if( cryptStatusError( tag ) )
679  return( tag );
680  if( tag == BER_OBJECT_IDENTIFIER )
681  {
682  /* Skip the AlgorithmIdentifier data and the following Name. For a
683  certificate we now have a SEQUENCE (from the Validity), for a CRL
684  a UTCTime or GeneralizedTime */
685  sSkip( stream, length );
686  readUniversal( stream );
687  tag = readTag( stream );
688  if( cryptStatusError( tag ) )
689  return( tag );
690  if( tag == BER_SEQUENCE )
691  {
692  *objectType = CRYPT_CERTTYPE_CERTIFICATE;
693  return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
694  }
695  if( tag == BER_TIME_UTC || tag == BER_TIME_GENERALIZED )
696  {
697  *objectType = CRYPT_CERTTYPE_CRL;
698  return( CRYPT_OK );
699  }
700  return( CRYPT_ERROR_BADDATA );
701  }
702  if( isLongData )
703  {
704  /* Beyond this point we shouldn't be seeing long-length objects */
705  return( CRYPT_ERROR_OVERFLOW );
706  }
707 #if 0 /* 21/10/08 Disabled, see comment at start */
708  if( tag == BER_OCTETSTRING )
709  {
710  *objectType = CRYPT_CERTTYPE_RTCS_REQUEST;
711  return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
712  }
713 #endif /* 0 */
714  if( tag == MAKE_CTAG( 1 ) )
715  {
716  *objectType = CRYPT_CERTTYPE_ATTRIBUTE_CERT;
717  return( CRYPT_OK );
718  }
719  if( tag == MAKE_CTAG_PRIMITIVE( 0 ) || \
720  tag == MAKE_CTAG_PRIMITIVE( 1 ) || \
721  ( tag >= MAKE_CTAG( 2 ) && tag <= MAKE_CTAG( 9 ) ) )
722  {
723  *objectType = CRYPT_CERTTYPE_REQUEST_CERT;
724  return( CRYPT_OK );
725  }
726  if( tag == BER_SET )
727  {
728  sSkip( stream, length );
729  readSequence( stream, NULL );
730  tag = readTag( stream );
731  if( cryptStatusError( tag ) )
732  return( tag );
733  if( tag == BER_OBJECT_IDENTIFIER )
734  {
735  *objectType = CRYPT_CERTTYPE_ATTRIBUTE_CERT;
736  return( CRYPT_OK );
737  }
738  if( tag == BER_SEQUENCE )
739  {
740  *objectType = CRYPT_CERTTYPE_CERTREQUEST;
741  return( CRYPT_OK );
742  }
743  return( CRYPT_ERROR_BADDATA );
744  }
745 
746 #if 0 /* 21/10/08 Disabled, see comment at start */
747  /* Read the next SEQUENCE. If it's followed by a yet another SEQUENCE
748  or a tag from [0] ... [3] it's an OCSP request */
749  readSequence( stream, NULL );
750  tag = readTag( stream );
751  if( cryptStatusError( tag ) )
752  return( tag );
753  if( tag == BER_SEQUENCE || \
754  ( tag >= MAKE_CTAG( 0 ) && tag <= MAKE_CTAG( 3 ) ) )
755  {
756  *objectType = CRYPT_CERTTYPE_OCSP_REQUEST;
757  return( CRYPT_OK );
758  }
759 #endif /* 0 */
760 
761  /* It's nothing identifiable */
762  return( CRYPT_ERROR_BADDATA );
763  }
764 #endif /* USE_CERTIFICATES */