cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
pkcs15_atrd.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib PKCS #15 Attribute Read Routines *
4 * Copyright Peter Gutmann 1996-2007 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "asn1.h"
11  #include "asn1_ext.h"
12  #include "keyset.h"
13  #include "pkcs15.h"
14 #else
15  #include "crypt.h"
16  #include "enc_dec/asn1.h"
17  #include "enc_dec/asn1_ext.h"
18  #include "keyset/keyset.h"
19  #include "keyset/pkcs15.h"
20 #endif /* Compiler-specific includes */
21 
22 #ifdef USE_PKCS15
23 
24 /* A macro to check that we're OK to read more data beyond this point */
25 
26 #define canContinue( stream, status, endPos ) \
27  ( cryptStatusOK( status ) && stell( stream ) < endPos )
28 
29 /* OID information used to read a PKCS #15 keyset */
30 
31 static const OID_INFO FAR_BSS dataObjectOIDinfo[] = {
33  { WILDCARD_OID, FALSE },
34  { NULL, 0 }, { NULL, 0 }
35  };
36 static const OID_INFO FAR_BSS cryptlibDataOIDinfo[] = {
37  { OID_CRYPTLIB_CONFIGDATA, CRYPT_IATTRIBUTE_CONFIGDATA },
38  { OID_CRYPTLIB_USERINDEX, CRYPT_IATTRIBUTE_USERINDEX },
39  { OID_CRYPTLIB_USERINFO, CRYPT_IATTRIBUTE_USERINFO },
41  { NULL, 0 }, { NULL, 0 }
42  };
43 
44 /* Permitted object subtypes. PKCS #15 uses context-specific tagging to
45  identify the subtypes within an object type so we store a list of
46  permitted tags for each object type */
47 
48 typedef struct {
49  PKCS15_OBJECT_TYPE type; /* Object type */
50  int subTypes[ 7 ]; /* Subtype tags */
51  } ALLOWED_ATTRIBUTE_TYPES;
52 
53 static const ALLOWED_ATTRIBUTE_TYPES allowedTypesTbl[] = {
57  CRYPT_ERROR, CRYPT_ERROR } },
61  CRYPT_ERROR, CRYPT_ERROR } },
63  { BER_SEQUENCE, CRYPT_ERROR, CRYPT_ERROR } },
65  { CRYPT_ERROR, CRYPT_ERROR } },
70  };
71 
72 /****************************************************************************
73 * *
74 * Utility Functions *
75 * *
76 ****************************************************************************/
77 
78 /* Read a sequence of PKCS #15 key identifiers */
79 
80 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
81 static int readKeyIdentifiers( INOUT STREAM *stream,
83  IN_LENGTH const int endPos )
84  {
85  int iterationCount, status;
86 
87  assert( isWritePtr( stream, sizeof( STREAM ) ) );
88  assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
89 
90  REQUIRES( endPos > 0 && endPos > stell( stream ) && \
91  endPos < MAX_INTLENGTH );
92 
93  for( status = CRYPT_OK, iterationCount = 0;
94  cryptStatusOK( status ) && stell( stream ) < endPos && \
95  iterationCount < FAILSAFE_ITERATIONS_MED; iterationCount++ )
96  {
97  long value;
98  int payloadLength;
99 
100  /* Read each identifier type and copy the useful ones into the PKCS
101  #15 information */
102  readSequence( stream, &payloadLength );
103  status = readShortInteger( stream, &value );
104  if( cryptStatusError( status ) )
105  return( status );
106  switch( value )
107  {
109  {
110  HASHFUNCTION_ATOMIC hashFunctionAtomic;
111  void *iAndSPtr = DUMMY_INIT_PTR;
112  int iAndSLength, hashSize;
113 
114  /* If we've already got the iAndSID, use that version
115  instead */
116  if( pkcs15infoPtr->iAndSIDlength > 0 )
117  {
118  status = readUniversal( stream );
119  continue;
120  }
121 
122  /* Hash the full issuerAndSerialNumber to get an iAndSID */
123  getHashAtomicParameters( CRYPT_ALGO_SHA1, 0,
124  &hashFunctionAtomic, &hashSize );
125  status = getStreamObjectLength( stream, &iAndSLength );
126  if( cryptStatusOK( status ) )
127  status = sMemGetDataBlock( stream, &iAndSPtr,
128  iAndSLength );
129  if( cryptStatusOK( status ) )
130  status = sSkip( stream, iAndSLength );
131  if( cryptStatusError( status ) )
132  return( status );
133  hashFunctionAtomic( pkcs15infoPtr->iAndSID, KEYID_SIZE,
134  iAndSPtr, iAndSLength );
135  pkcs15infoPtr->iAndSIDlength = hashSize;
136  break;
137  }
138 
140  status = readOctetString( stream, pkcs15infoPtr->keyID,
141  &pkcs15infoPtr->keyIDlength,
142  8, CRYPT_MAX_HASHSIZE );
143  break;
144 
146  /* If we've already got the iAndSID by hashing the
147  issuerAndSerialNumber, use that version instead */
148  if( pkcs15infoPtr->iAndSIDlength > 0 )
149  {
150  status = readUniversal( stream );
151  continue;
152  }
153  status = readOctetString( stream, pkcs15infoPtr->iAndSID,
154  &pkcs15infoPtr->iAndSIDlength,
156  break;
157 
159  status = readOctetString( stream, pkcs15infoPtr->issuerNameID,
160  &pkcs15infoPtr->issuerNameIDlength,
162  break;
163 
165  status = readOctetString( stream, pkcs15infoPtr->subjectNameID,
166  &pkcs15infoPtr->subjectNameIDlength,
168  break;
169 
170  case PKCS15_KEYID_PGP2:
171  status = readOctetString( stream, pkcs15infoPtr->pgp2KeyID,
172  &pkcs15infoPtr->pgp2KeyIDlength,
174  break;
175 
177  status = readOctetString( stream, pkcs15infoPtr->openPGPKeyID,
178  &pkcs15infoPtr->openPGPKeyIDlength,
180  break;
181 
182  default:
183  status = readUniversal( stream );
184  }
185  }
186  if( iterationCount >= FAILSAFE_ITERATIONS_MED )
187  {
188  /* This could be either an internal error or some seriously
189  malformed data, since we can't tell without human intervention
190  we throw a debug exception but otherwise treat it as bad data */
191  DEBUG_DIAG(( "Encountered more than %d key IDs",
192  FAILSAFE_ITERATIONS_MED ));
193  assert( DEBUG_WARN );
194  return( CRYPT_ERROR_BADDATA );
195  }
196 
197  return( status );
198  }
199 
200 /****************************************************************************
201 * *
202 * Read PKCS #15 Attributes *
203 * *
204 ****************************************************************************/
205 
206 /* Read public/private key attributes */
207 
208 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
209 static int readPubkeyAttributes( INOUT STREAM *stream,
210  INOUT PKCS15_INFO *pkcs15infoPtr,
211  IN_LENGTH const int endPos,
212  const BOOLEAN isPubKeyObject )
213  {
214  int usageFlags, status;
215 
216  assert( isWritePtr( stream, sizeof( STREAM ) ) );
217  assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
218 
219  REQUIRES( endPos > 0 && endPos > stell( stream ) && \
220  endPos < MAX_INTLENGTH );
221 
222  status = readBitString( stream, &usageFlags ); /* Usage flags */
223  if( canContinue( stream, status, endPos ) && /* Native flag */
224  peekTag( stream ) == BER_BOOLEAN )
225  status = readUniversal( stream );
226  if( canContinue( stream, status, endPos ) && /* Access flags */
227  peekTag( stream ) == BER_BITSTRING )
228  status = readUniversal( stream );
229  if( canContinue( stream, status, endPos ) && /* Key reference */
230  peekTag( stream ) == BER_INTEGER )
231  status = readUniversal( stream );
232  if( canContinue( stream, status, endPos ) && /* Start date */
233  peekTag( stream ) == BER_TIME_GENERALIZED )
234  status = readGeneralizedTime( stream, &pkcs15infoPtr->validFrom );
235  if( canContinue( stream, status, endPos ) && /* End date */
236  peekTag( stream ) == MAKE_CTAG( CTAG_KA_VALIDTO ) )
237  status = readGeneralizedTimeTag( stream, &pkcs15infoPtr->validTo,
238  CTAG_KA_VALIDTO );
239  if( cryptStatusError( status ) )
240  return( status );
241  if( isPubKeyObject )
242  pkcs15infoPtr->pubKeyUsage = usageFlags;
243  else
244  pkcs15infoPtr->privKeyUsage = usageFlags;
245 
246  return( CRYPT_OK );
247  }
248 
249 /* Read certificate attributes */
250 
251 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
252 static int readCertAttributes( INOUT STREAM *stream,
253  INOUT PKCS15_INFO *pkcs15infoPtr,
254  IN_LENGTH const int endPos )
255  {
256  int length, status = CRYPT_OK;
257 
258  assert( isWritePtr( stream, sizeof( STREAM ) ) );
259  assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
260 
261  REQUIRES( endPos > 0 && endPos > stell( stream ) && \
262  endPos < MAX_INTLENGTH );
263 
264  if( peekTag( stream ) == BER_BOOLEAN ) /* Authority flag */
265  status = readUniversal( stream );
266  if( canContinue( stream, status, endPos ) && /* Identifier */
267  peekTag( stream ) == BER_SEQUENCE )
268  status = readUniversal( stream );
269  if( canContinue( stream, status, endPos ) && /* Thumbprint */
270  peekTag( stream ) == MAKE_CTAG( CTAG_CA_DUMMY ) )
271  status = readUniversal( stream );
272  if( canContinue( stream, status, endPos ) && /* Trusted usage */
273  peekTag( stream ) == MAKE_CTAG( CTAG_CA_TRUSTED_USAGE ) )
274  {
275  readConstructed( stream, NULL, CTAG_CA_TRUSTED_USAGE );
276  status = readBitString( stream, &pkcs15infoPtr->trustedUsage );
277  }
278  if( canContinue( stream, status, endPos ) && /* Identifiers */
279  peekTag( stream ) == MAKE_CTAG( CTAG_CA_IDENTIFIERS ) )
280  {
281  status = readConstructed( stream, &length, CTAG_CA_IDENTIFIERS );
282  if( cryptStatusOK( status ) )
283  status = readKeyIdentifiers( stream, pkcs15infoPtr,
284  stell( stream ) + length );
285  }
286  if( canContinue( stream, status, endPos ) && /* Implicitly trusted */
287  peekTag( stream ) == MAKE_CTAG_PRIMITIVE( CTAG_CA_TRUSTED_IMPLICIT ) )
288  status = readBooleanTag( stream, &pkcs15infoPtr->implicitTrust,
290  if( canContinue( stream, status, endPos ) && /* Validity */
291  peekTag( stream ) == MAKE_CTAG( CTAG_CA_VALIDTO ) )
292  {
293  /* Due to miscommunication between PKCS #15 and 7816-15 there are
294  two ways to encode the validity information for certificates, one
295  based on the format used elsewhere in PKCS #15 (for PKCS #15) and
296  the other based on the format used in certificates (for 7816-15).
297  Luckily they can be distinguished by the tagging type */
298  readConstructed( stream, NULL, CTAG_CA_VALIDTO );
299  readUTCTime( stream, &pkcs15infoPtr->validFrom );
300  status = readUTCTime( stream, &pkcs15infoPtr->validTo );
301  }
302  else
303  {
304  if( canContinue( stream, status, endPos ) && /* Start date */
305  peekTag( stream ) == BER_TIME_GENERALIZED )
306  status = readGeneralizedTime( stream, &pkcs15infoPtr->validFrom );
307  if( canContinue( stream, status, endPos ) && /* End date */
308  peekTag( stream ) == MAKE_CTAG_PRIMITIVE( CTAG_CA_VALIDTO ) )
309  status = readGeneralizedTimeTag( stream, &pkcs15infoPtr->validTo,
310  CTAG_CA_VALIDTO );
311  }
312 
313  return( status );
314  }
315 
316 /* Read an object's attributes */
317 
318 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
319 int readObjectAttributes( INOUT STREAM *stream,
320  INOUT PKCS15_INFO *pkcs15infoPtr,
321  IN_ENUM( PKCS15_OBJECT ) const PKCS15_OBJECT_TYPE type,
323  {
324  const ALLOWED_ATTRIBUTE_TYPES *allowedTypeInfo;
325  BOOLEAN skipDataRead = TRUE, isCryptlibData = FALSE;
326  int length, outerLength, endPos, value, tag, i, status;
327 
328  assert( isWritePtr( stream, sizeof( STREAM ) ) );
329  assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
330 
331  REQUIRES( type > PKCS15_OBJECT_NONE && type < PKCS15_OBJECT_LAST );
332  REQUIRES( errorInfo != NULL );
333 
334  /* Clear the return value */
335  memset( pkcs15infoPtr, 0, sizeof( PKCS15_INFO ) );
336 
337  /* Find the allowed-subtype information for this object type */
338  for( i = 0; \
339  allowedTypesTbl[ i ].type != type && \
340  allowedTypesTbl[ i ].type != PKCS15_OBJECT_NONE && \
341  i < FAILSAFE_ARRAYSIZE( allowedTypesTbl, ALLOWED_ATTRIBUTE_TYPES );
342  i++ );
343  ENSURES( i < FAILSAFE_ARRAYSIZE( allowedTypesTbl, ALLOWED_ATTRIBUTE_TYPES ) );
344  allowedTypeInfo = &allowedTypesTbl[ i ];
345 
346  /* Make sure that this is a subtype that we can handle */
347  tag = peekTag( stream );
348  if( cryptStatusError( tag ) )
349  return( tag );
350  status = readGenericHole( stream, &outerLength, MIN_OBJECT_SIZE,
351  DEFAULT_TAG );
352  if( cryptStatusError( status ) )
353  return( status );
354  for( i = 0; allowedTypeInfo->subTypes[ i ] != CRYPT_ERROR && \
355  i < FAILSAFE_ITERATIONS_SMALL; i++ )
356  {
357  /* If this is a recognised subtype, process the attribute data */
358  if( allowedTypeInfo->subTypes[ i ] == tag )
359  {
360  skipDataRead = FALSE;
361  break;
362  }
363  }
364  ENSURES( i < FAILSAFE_ITERATIONS_SMALL );
365 
366  /* Process the PKCS15CommonObjectAttributes */
367  status = readSequence( stream, &length );
368 #if 0 /* 12/8/10 Only ever present in one pre-release product, now fixed */
369  if( cryptStatusOK( status ) && outerLength == sizeofObject( length ) )
370  {
371  /* Due to a disagreement over IMPLICIT vs. EXPLICIT tagging for the
372  parameterised types used in PKCS #15 based on an error that was
373  in the specification up until version 1.2 (see section F.2 of the
374  specification) some implementations have an extra layer of
375  encapsulation after the type tag. If the inner SEQUENCE fits
376  exactly into the outer wrapper then the tagging used was EXPLICIT
377  and we need to dig down another level */
378  status = readSequence( stream, &length );
379  }
380 #endif /* 0 */
381  if( cryptStatusOK( status ) && length > 0 )
382  {
383  endPos = stell( stream ) + length;
384 
385  /* Read the label if it's present and skip anything else */
386  if( peekTag( stream ) == BER_STRING_UTF8 )
387  {
388  status = readCharacterString( stream,
389  pkcs15infoPtr->label, CRYPT_MAX_TEXTSIZE,
390  &pkcs15infoPtr->labelLength, BER_STRING_UTF8 );
391  }
392  if( canContinue( stream, status, endPos ) )
393  status = sseek( stream, endPos );
394  }
395  if( cryptStatusError( status ) )
396  {
397  retExt( status,
398  ( status, errorInfo,
399  "Invalid PKCS #15 common object attributes" ) );
400  }
401 
402  /* Process the PKCS15CommonXXXAttributes */
403  status = readSequence( stream, &length );
404  if( cryptStatusError( status ) )
405  return( status );
406  endPos = stell( stream ) + length;
407  switch( type )
408  {
411  /* It's a public/private-key object, read the ID and assorted
412  flags */
413  status = readOctetString( stream, pkcs15infoPtr->iD,
414  &pkcs15infoPtr->iDlength,
415  1, CRYPT_MAX_HASHSIZE );
416  if( cryptStatusOK( status ) && \
417  canContinue( stream, status, endPos ) )
418  {
419  status = readPubkeyAttributes( stream, pkcs15infoPtr,
420  endPos,
421  ( type == PKCS15_OBJECT_PUBKEY ) ? \
422  TRUE : FALSE );
423  }
424  if( cryptStatusError( status ) )
425  {
426  retExt( status,
427  ( status, errorInfo,
428  "Invalid PKCS #15 public/private-key "
429  "attributes" ) );
430  }
431  break;
432 
433  case PKCS15_OBJECT_CERT:
434  /* It's a certificate object, read the ID and assorted flags */
435  status = readOctetString( stream, pkcs15infoPtr->iD,
436  &pkcs15infoPtr->iDlength,
437  1, CRYPT_MAX_HASHSIZE );
438  if( cryptStatusOK( status ) && \
439  canContinue( stream, status, endPos ) )
440  {
441  status = readCertAttributes( stream, pkcs15infoPtr,
442  endPos );
443  }
444  if( cryptStatusError( status ) )
445  {
446  retExt( status,
447  ( status, errorInfo,
448  "Invalid PKCS #15 certificate attributes" ) );
449  }
450  break;
451 
453  /* It's a secret-key object, there are no common attributes of interest
454  present */
455  break;
456 
457  case PKCS15_OBJECT_DATA:
458  /* If it's a data object then all of the attributes are
459  optional. If it's specifically a cryptlib data object then
460  it'll be identified via the cryptlib OID */
461  if( length <= 0 )
462  break;
463  if( peekTag( stream ) == BER_STRING_UTF8 )
464  status = readUniversal( stream ); /* Skip application name */
465  if( canContinue( stream, status, endPos ) && \
466  peekTag( stream ) == BER_OBJECT_IDENTIFIER )
467  {
468  status = readOID( stream, dataObjectOIDinfo,
469  FAILSAFE_ARRAYSIZE( dataObjectOIDinfo, \
470  OID_INFO ), &value );
471  if( cryptStatusOK( status ) && value == TRUE )
472  isCryptlibData = TRUE;
473  }
474  break;
475 
476  default:
477  retIntError();
478  }
479  if( cryptStatusError( status ) )
480  {
481  retExt( status,
482  ( status, errorInfo,
483  "Invalid PKCS #15 common type attributes" ) );
484  }
485 
486  /* Skip any additional attribute information that may be present */
487  if( stell( stream ) < endPos )
488  {
489  status = sseek( stream, endPos );
490  if( cryptStatusError( status ) )
491  return( status );
492  }
493 
494  /* For now we use the iD as the keyID, this may be overridden later if
495  there's a real keyID present */
496  if( pkcs15infoPtr->iDlength > 0 )
497  {
498  memcpy( pkcs15infoPtr->keyID, pkcs15infoPtr->iD,
499  pkcs15infoPtr->iDlength );
500  pkcs15infoPtr->keyIDlength = pkcs15infoPtr->iDlength;
501  }
502 
503  /* Skip the subclass attributes if present */
504  if( peekTag( stream ) == MAKE_CTAG( CTAG_OB_SUBCLASSATTR ) )
505  {
506  status = readUniversal( stream );
507  if( cryptStatusError( status ) )
508  {
509  retExt( status,
510  ( status, errorInfo,
511  "Invalid PKCS #15 subclass attributes" ) );
512  }
513  }
514 
515  /* Process the type attributes, which just consists of remembering where
516  the payload starts */
517  readConstructed( stream, NULL, CTAG_OB_TYPEATTR );
518  status = readSequence( stream, &length );
519  if( cryptStatusError( status ) )
520  return( status );
521  endPos = stell( stream ) + length;
522  if( skipDataRead )
523  {
524  /* It's a non-recognised object subtype, skip it */
525  return( ( stell( stream ) < endPos ) ? \
526  sseek( stream, endPos ) : CRYPT_OK );
527  }
528  if( peekTag( stream ) == MAKE_CTAG( CTAG_OV_DIRECT ) )
529  {
530  /* Parameterised types have special tagging requirements when using
531  context-specific tags and the declaration is a "Tag Type" (for
532  example for the "direct" choice for the ObjectValue type) and the
533  "Type" in the "Tag Type" is a "DummyReference". In this case the
534  context tag is encoded as an EXPLICIT rather than IMPLCIIT tag
535  (see section F.2 of PKCS #15 v1.2 and newer). The only case where
536  this occurs is for the ObjectValue.direct option.
537 
538  This is complicated by the fact that versions of PKCS #15 before
539  v1.2 erroneously stated that all context-specific tags in
540  parameterised types should use EXPLICIT tagging, however no
541  (known) implementation ever did this.
542 
543  What this double error means is that existing implementations get
544  things almost right, the exception being ObjectValue.direct, which
545  does require an EXPLICIT tag. To deal with this, we check for the
546  presence of the optional tag and skip it if it's present */
547  status = readConstructed( stream, &length, CTAG_OV_DIRECT );
548  if( cryptStatusError( status ) )
549  return( status );
550  }
551  switch( type )
552  {
554  pkcs15infoPtr->pubKeyOffset = stell( stream );
555  break;
556 
558  pkcs15infoPtr->privKeyOffset = stell( stream );
559  break;
560 
561  case PKCS15_OBJECT_CERT:
562  pkcs15infoPtr->certOffset = stell( stream );
563  break;
564 
566  pkcs15infoPtr->secretKeyOffset = stell( stream );
567  break;
568 
569  case PKCS15_OBJECT_DATA:
570  /* If it's not cryptlib data, we can't do much with it */
571  if( !isCryptlibData )
572  break;
573 
574  /* It's a cryptlib data object, extract the contents */
575  status = readOID( stream, cryptlibDataOIDinfo,
576  FAILSAFE_ARRAYSIZE( cryptlibDataOIDinfo, \
577  OID_INFO ),
578  &value );
579  if( cryptStatusOK( status ) && \
580  ( value == CRYPT_IATTRIBUTE_CONFIGDATA || \
581  value == CRYPT_IATTRIBUTE_USERINDEX ) )
582  {
583  /* The configuration data and user index are SEQUENCEs of
584  objects */
585  status = readSequence( stream, NULL );
586  }
587  if( cryptStatusError( status ) )
588  break;
589  if( value == CRYPT_ATTRIBUTE_NONE )
590  {
591  /* It's a non-recognised cryptlib data subtype, skip it */
592  break;
593  }
594  pkcs15infoPtr->dataOffset = stell( stream );
595  pkcs15infoPtr->dataType = value;
596  break;
597 
598  default:
599  retIntError();
600  }
601  if( cryptStatusError( status ) )
602  {
603  retExt( status,
604  ( status, errorInfo,
605  "Invalid PKCS #15 type attributes" ) );
606  }
607 
608  /* Skip the object data and any additional attribute information that
609  may be present */
610  if( stell( stream ) < endPos )
611  return( sseek( stream, endPos ) );
612 
613  return( CRYPT_OK );
614  }
615 #endif /* USE_PKCS15 */