1 /****************************************************************************
2 *																			*
3 *					cryptlib PKCS #15 Attribute Read Routines				*
4 *						Copyright Peter Gutmann 1996-2014					*
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 /* OID information used to read a PKCS #15 keyset */
25 
26 static const OID_INFO FAR_BSS dataObjectOIDinfo[] = {
27 	{ OID_CRYPTLIB_CONTENTTYPE, TRUE },
28 	{ WILDCARD_OID, FALSE },
29 	{ NULL, 0 }, { NULL, 0 }
30 	};
31 static const OID_INFO FAR_BSS cryptlibDataOIDinfo[] = {
32 	{ OID_CRYPTLIB_CONFIGDATA, CRYPT_IATTRIBUTE_CONFIGDATA },
33 	{ OID_CRYPTLIB_USERINDEX, CRYPT_IATTRIBUTE_USERINDEX },
34 	{ OID_CRYPTLIB_USERINFO, CRYPT_IATTRIBUTE_USERINFO },
35 	{ WILDCARD_OID, CRYPT_ATTRIBUTE_NONE },
36 	{ NULL, 0 }, { NULL, 0 }
37 	};
38 
39 /* Permitted object subtypes.  PKCS #15 uses context-specific tagging to
40    identify the subtypes within an object type so we store a list of
41    permitted tags for each object type */
42 
43 typedef struct {
44 	PKCS15_OBJECT_TYPE type;	/* Object type */
45 	int subTypes[ 7 ];			/* Subtype tags */
46 	} ALLOWED_ATTRIBUTE_TYPES;
47 
48 static const ALLOWED_ATTRIBUTE_TYPES allowedTypesTbl[] = {
49 	{ PKCS15_OBJECT_PUBKEY,
50 	  { BER_SEQUENCE, MAKE_CTAG( CTAG_PK_ECC ), MAKE_CTAG( CTAG_PK_DH ),
51 	    MAKE_CTAG( CTAG_PK_DSA ),
52 		CRYPT_ERROR, CRYPT_ERROR } },
53 	{ PKCS15_OBJECT_PRIVKEY,
54 	  { BER_SEQUENCE, MAKE_CTAG( CTAG_PK_ECC ), MAKE_CTAG( CTAG_PK_DH ),
55 	    MAKE_CTAG( CTAG_PK_DSA ),
56 		CRYPT_ERROR, CRYPT_ERROR } },
57 	{ PKCS15_OBJECT_CERT,
58 	  { BER_SEQUENCE, CRYPT_ERROR, CRYPT_ERROR } },
59 	{ PKCS15_OBJECT_SECRETKEY,
60 	  { CRYPT_ERROR, CRYPT_ERROR } },
61 	{ PKCS15_OBJECT_DATA,
62 	  { MAKE_CTAG( CTAG_DO_OIDDO ), CRYPT_ERROR, CRYPT_ERROR } },
63 	{ PKCS15_OBJECT_NONE, { CRYPT_ERROR, CRYPT_ERROR } },
64 		{ PKCS15_OBJECT_NONE, { CRYPT_ERROR, CRYPT_ERROR } }
65 	};
66 
67 /****************************************************************************
68 *																			*
69 *								Utility Functions							*
70 *																			*
71 ****************************************************************************/
72 
73 /* Read a sequence of PKCS #15 key identifiers */
74 
75 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
readKeyIdentifiers(INOUT STREAM * stream,INOUT PKCS15_INFO * pkcs15infoPtr,IN_LENGTH const int endPos)76 static int readKeyIdentifiers( INOUT STREAM *stream,
77 							   INOUT PKCS15_INFO *pkcs15infoPtr,
78 							   IN_LENGTH const int endPos )
79 	{
80 	int iterationCount, status;
81 
82 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
83 	assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
84 
85 	REQUIRES( endPos > 0 && endPos > stell( stream ) && \
86 			  endPos < MAX_BUFFER_SIZE );
87 
88 	for( status = CRYPT_OK, iterationCount = 0;
89 		 cryptStatusOK( status ) && stell( stream ) < endPos && \
90 			iterationCount < FAILSAFE_ITERATIONS_MED; iterationCount++ )
91 		{
92 		long value;
93 		int payloadLength;
94 
95 		/* Read each identifier type and copy the useful ones into the PKCS
96 		   #15 information */
97 		readSequence( stream, &payloadLength );
98 		status = readShortInteger( stream, &value );
99 		if( cryptStatusError( status ) )
100 			return( status );
101 		switch( value )
102 			{
103 			case PKCS15_KEYID_ISSUERANDSERIALNUMBER:
104 				{
105 				HASH_FUNCTION_ATOMIC hashFunctionAtomic;
106 				void *iAndSPtr DUMMY_INIT_PTR;
107 				int iAndSLength, hashSize;
108 
109 				/* If we've already got the iAndSID, use that version
110 				   instead */
111 				if( pkcs15infoPtr->iAndSIDlength > 0 )
112 					{
113 					status = readUniversal( stream );
114 					continue;
115 					}
116 
117 				/* Hash the full issuerAndSerialNumber to get an iAndSID */
118 				getHashAtomicParameters( CRYPT_ALGO_SHA1, 0,
119 										 &hashFunctionAtomic, &hashSize );
120 				status = getStreamObjectLength( stream, &iAndSLength );
121 				if( cryptStatusOK( status ) )
122 					status = sMemGetDataBlock( stream, &iAndSPtr,
123 											   iAndSLength );
124 				if( cryptStatusOK( status ) )
125 					{
126 					status = sSkip( stream, iAndSLength,
127 									MAX_INTLENGTH_SHORT );
128 					}
129 				if( cryptStatusError( status ) )
130 					return( status );
131 				hashFunctionAtomic( pkcs15infoPtr->iAndSID, KEYID_SIZE,
132 									iAndSPtr, iAndSLength );
133 				pkcs15infoPtr->iAndSIDlength = hashSize;
134 				break;
135 				}
136 
137 			case PKCS15_KEYID_SUBJECTKEYIDENTIFIER:
138 				status = readOctetString( stream, pkcs15infoPtr->keyID,
139 										  &pkcs15infoPtr->keyIDlength,
140 										  8, CRYPT_MAX_HASHSIZE );
141 				break;
142 
143 			case PKCS15_KEYID_ISSUERANDSERIALNUMBERHASH:
144 				/* If we've already got the iAndSID by hashing the
145 				   issuerAndSerialNumber, use that version instead */
146 				if( pkcs15infoPtr->iAndSIDlength > 0 )
147 					{
148 					status = readUniversal( stream );
149 					continue;
150 					}
151 				status = readOctetString( stream, pkcs15infoPtr->iAndSID,
152 										  &pkcs15infoPtr->iAndSIDlength,
153 										  KEYID_SIZE, KEYID_SIZE );
154 				break;
155 
156 			case PKCS15_KEYID_ISSUERNAMEHASH:
157 				status = readOctetString( stream, pkcs15infoPtr->issuerNameID,
158 										  &pkcs15infoPtr->issuerNameIDlength,
159 										  KEYID_SIZE, KEYID_SIZE );
160 				break;
161 
162 			case PKCS15_KEYID_SUBJECTNAMEHASH:
163 				status = readOctetString( stream, pkcs15infoPtr->subjectNameID,
164 										  &pkcs15infoPtr->subjectNameIDlength,
165 										  KEYID_SIZE, KEYID_SIZE );
166 				break;
167 
168 			case PKCS15_KEYID_PGP2:
169 				status = readOctetString( stream, pkcs15infoPtr->pgp2KeyID,
170 										  &pkcs15infoPtr->pgp2KeyIDlength,
171 										  PGP_KEYID_SIZE, PGP_KEYID_SIZE );
172 				break;
173 
174 			case PKCS15_KEYID_OPENPGP:
175 				status = readOctetString( stream, pkcs15infoPtr->openPGPKeyID,
176 										  &pkcs15infoPtr->openPGPKeyIDlength,
177 										  PGP_KEYID_SIZE, PGP_KEYID_SIZE );
178 				break;
179 
180 			default:
181 				status = readUniversal( stream );
182 			}
183 		}
184 	if( iterationCount >= FAILSAFE_ITERATIONS_MED )
185 		{
186 		/* This could be either an internal error or some seriously
187 		   malformed data, since we can't tell without human intervention
188 		   we throw a debug exception but otherwise treat it as bad data */
189 		DEBUG_DIAG(( "Encountered more than %d key IDs",
190 					 FAILSAFE_ITERATIONS_MED ));
191 		assert( DEBUG_WARN );
192 		return( CRYPT_ERROR_BADDATA );
193 		}
194 
195 	return( status );
196 	}
197 
198 /****************************************************************************
199 *																			*
200 *							Read PKCS #15 Attributes						*
201 *																			*
202 ****************************************************************************/
203 
204 /* Read public/private key attributes */
205 
206 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
readPubkeyAttributes(INOUT STREAM * stream,INOUT PKCS15_INFO * pkcs15infoPtr,IN_LENGTH const int endPos,const BOOLEAN isPubKeyObject)207 static int readPubkeyAttributes( INOUT STREAM *stream,
208 								 INOUT PKCS15_INFO *pkcs15infoPtr,
209 								 IN_LENGTH const int endPos,
210 								 const BOOLEAN isPubKeyObject )
211 	{
212 	int usageFlags, tag, status;
213 
214 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
215 	assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
216 
217 	REQUIRES( endPos > 0 && endPos > stell( stream ) && \
218 			  endPos < MAX_BUFFER_SIZE );
219 
220 	status = readBitString( stream, &usageFlags );			/* Usage flags */
221 	if( checkStatusLimitsPeekTag( stream, status, tag, endPos ) && \
222 		tag == BER_BOOLEAN )								/* Native flag */
223 		status = readUniversal( stream );
224 	if( checkStatusLimitsPeekTag( stream, status, tag, endPos ) && \
225 		tag == BER_BITSTRING )								/* Access flags */
226 		status = readUniversal( stream );
227 	if( checkStatusLimitsPeekTag( stream, status, tag, endPos ) && \
228 		tag == BER_INTEGER )								/* Key reference */
229 		status = readUniversal( stream );
230 	if( checkStatusLimitsPeekTag( stream, status, tag, endPos ) && \
231 		tag == BER_TIME_GENERALIZED )						/* Start date */
232 		status = readGeneralizedTime( stream, &pkcs15infoPtr->validFrom );
233 	if( checkStatusLimitsPeekTag( stream, status, tag, endPos ) && \
234 		tag == MAKE_CTAG( CTAG_KA_VALIDTO ) )				/* End date */
235 		status = readGeneralizedTimeTag( stream, &pkcs15infoPtr->validTo,
236 										 CTAG_KA_VALIDTO );
237 	if( cryptStatusError( status ) )
238 		return( status );
239 	if( isPubKeyObject )
240 		pkcs15infoPtr->pubKeyUsage = usageFlags;
241 	else
242 		pkcs15infoPtr->privKeyUsage = usageFlags;
243 
244 	return( CRYPT_OK );
245 	}
246 
247 /* Read certificate attributes */
248 
249 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
readCertAttributes(INOUT STREAM * stream,INOUT PKCS15_INFO * pkcs15infoPtr,IN_LENGTH const int endPos)250 static int readCertAttributes( INOUT STREAM *stream,
251 							   INOUT PKCS15_INFO *pkcs15infoPtr,
252 							   IN_LENGTH const int endPos )
253 	{
254 	int tag, length, status = CRYPT_OK;
255 
256 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
257 	assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
258 
259 	REQUIRES( endPos > 0 && endPos > stell( stream ) && \
260 			  endPos < MAX_BUFFER_SIZE );
261 
262 	if( checkStatusPeekTag( stream, status, tag ) && \
263 		tag == BER_BOOLEAN )								/* Authority flag */
264 		status = readUniversal( stream );
265 	if( checkStatusLimitsPeekTag( stream, status, tag, endPos ) && \
266 		tag == BER_SEQUENCE )								/* Identifier */
267 		status = readUniversal( stream );
268 	if( checkStatusLimitsPeekTag( stream, status, tag, endPos ) && \
269 		tag == MAKE_CTAG( CTAG_CA_DUMMY ) )					/* Thumbprint */
270 		status = readUniversal( stream );
271 	if( checkStatusLimitsPeekTag( stream, status, tag, endPos ) && \
272 		tag == MAKE_CTAG( CTAG_CA_TRUSTED_USAGE ) )			/* Trusted usage */
273 		{
274 		readConstructed( stream, NULL, CTAG_CA_TRUSTED_USAGE );
275 		status = readBitString( stream, &pkcs15infoPtr->trustedUsage );
276 		}
277 	if( checkStatusLimitsPeekTag( stream, status, tag, endPos ) && \
278 		tag == MAKE_CTAG( CTAG_CA_IDENTIFIERS ) )			/* Identifiers */
279 		{
280 		status = readConstructed( stream, &length, CTAG_CA_IDENTIFIERS );
281 		if( cryptStatusOK( status ) && length > 0 )
282 			{
283 			status = readKeyIdentifiers( stream, pkcs15infoPtr,
284 										 stell( stream ) + length );
285 			}
286 		}
287 	if( checkStatusLimitsPeekTag( stream, status, tag, endPos ) && \
288 		tag == MAKE_CTAG_PRIMITIVE( CTAG_CA_TRUSTED_IMPLICIT ) )
289 		{													/* Implicitly trusted */
290 		status = readBooleanTag( stream, &pkcs15infoPtr->implicitTrust,
291 								 CTAG_CA_TRUSTED_IMPLICIT );
292 		}
293 	if( checkStatusLimitsPeekTag( stream, status, tag, endPos ) && \
294 		tag == MAKE_CTAG( CTAG_CA_VALIDTO ) )				/* Validity */
295 		{
296 		/* Due to miscommunication between PKCS #15 and 7816-15 there are
297 		   two ways to encode the validity information for certificates, one
298 		   based on the format used elsewhere in PKCS #15 (for PKCS #15) and
299 		   the other based on the format used in certificates (for 7816-15).
300 		   Luckily they can be distinguished by the tagging type */
301 		readConstructed( stream, NULL, CTAG_CA_VALIDTO );
302 		readUTCTime( stream, &pkcs15infoPtr->validFrom );
303 		status = readUTCTime( stream, &pkcs15infoPtr->validTo );
304 		}
305 	else
306 		{
307 		if( checkStatusLimitsPeekTag( stream, status, tag, endPos ) && \
308 			tag == BER_TIME_GENERALIZED )					/* Start date */
309 			status = readGeneralizedTime( stream, &pkcs15infoPtr->validFrom );
310 		if( checkStatusLimitsPeekTag( stream, status, tag, endPos ) && \
311 			tag == MAKE_CTAG_PRIMITIVE( CTAG_CA_VALIDTO ) )	/* End date */
312 			status = readGeneralizedTimeTag( stream, &pkcs15infoPtr->validTo,
313 											 CTAG_CA_VALIDTO );
314 		}
315 
316 	return( cryptStatusError( status ) ? status : CRYPT_OK );
317 	}		/* checkStatusLimitsPeekTag() can return tag as status */
318 
319 /* Read an object's attributes */
320 
321 CHECK_RETVAL_SPECIAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
readClassAttributes(INOUT STREAM * stream,INOUT PKCS15_INFO * pkcs15infoPtr,IN_ENUM (PKCS15_OBJECT)const PKCS15_OBJECT_TYPE type)322 static int readClassAttributes( INOUT STREAM *stream,
323 								INOUT PKCS15_INFO *pkcs15infoPtr,
324 								IN_ENUM( PKCS15_OBJECT ) \
325 									const PKCS15_OBJECT_TYPE type )
326 	{
327 	BOOLEAN isCryptlibObject = FALSE;
328 	int tag, length, endPos, status;
329 
330 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
331 	assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
332 
333 	REQUIRES( type > PKCS15_OBJECT_NONE && type < PKCS15_OBJECT_LAST );
334 
335 	/* Read the attribute wrapper.  Since there may be no attributes present,
336 	   we use readSequenceZ() */
337 	status = readSequenceZ( stream, &length );
338 	if( cryptStatusError( status ) )
339 		return( status );
340 	if( length <= 0 )
341 		{
342 		/* Secret-key objects have no attributes of interest, data objects
343 		   have only optional attributes, so a zero length is OK */
344 		if( type == PKCS15_OBJECT_SECRETKEY || type == PKCS15_OBJECT_DATA )
345 			return( CRYPT_OK );
346 
347 		/* For anything else, a zero length is an error */
348 		return( CRYPT_ERROR_BADDATA );
349 		}
350 	endPos = stell( stream ) + length;
351 
352 	/* Process per-object-type attributes */
353 	switch( type )
354 		{
355 		case PKCS15_OBJECT_PUBKEY:
356 		case PKCS15_OBJECT_PRIVKEY:
357 			/* It's a public/private-key object, read the ID and assorted
358 			   flags */
359 			if( length < sizeofObject( MIN_NAME_LENGTH ) )
360 				return( CRYPT_ERROR_BADDATA );
361 			status = readOctetString( stream, pkcs15infoPtr->iD,
362 									  &pkcs15infoPtr->iDlength,
363 									  MIN_NAME_LENGTH, CRYPT_MAX_HASHSIZE );
364 			if( cryptStatusOK( status ) && stell( stream ) < endPos )
365 				{
366 				status = readPubkeyAttributes( stream, pkcs15infoPtr,
367 											endPos,
368 											( type == PKCS15_OBJECT_PUBKEY ) ? \
369 											TRUE : FALSE );
370 				}
371 			break;
372 
373 		case PKCS15_OBJECT_CERT:
374 			/* It's a certificate object, read the ID and assorted flags */
375 			if( length < sizeofObject( MIN_NAME_LENGTH ) )
376 				return( CRYPT_ERROR_BADDATA );
377 			status = readOctetString( stream, pkcs15infoPtr->iD,
378 									  &pkcs15infoPtr->iDlength,
379 									  MIN_NAME_LENGTH, CRYPT_MAX_HASHSIZE );
380 			if( cryptStatusOK( status ) && stell( stream ) < endPos )
381 				{
382 				status = readCertAttributes( stream, pkcs15infoPtr,
383 											 endPos );
384 				}
385 			break;
386 
387 		case PKCS15_OBJECT_SECRETKEY:
388 			/* It's a secret-key object, there are no attributes of interest
389 			   present */
390 			break;
391 
392 		case PKCS15_OBJECT_DATA:
393 			/* If it's a cryptlib data object then it'll be identified via
394 			   the cryptlib OID */
395 			if( checkStatusPeekTag( stream, status, tag ) && \
396 				tag == BER_STRING_UTF8 )
397 				{
398 				/* Skip application name */
399 				status = readUniversal( stream );
400 				}
401 			if( checkStatusLimitsPeekTag( stream, status, tag, endPos ) && \
402 				tag == BER_OBJECT_IDENTIFIER )
403 				{
404 				int value;
405 
406 				status = readOID( stream, dataObjectOIDinfo,
407 								  FAILSAFE_ARRAYSIZE( dataObjectOIDinfo, \
408 													  OID_INFO ), &value );
409 				if( cryptStatusOK( status ) && value == TRUE )
410 					isCryptlibObject = TRUE;
411 				}
412 			break;
413 
414 		case PKCS15_OBJECT_UNRECOGNISED:
415 			/* It's an unrecognised object type, we don't know what to do
416 			   with any attributes that may be present */
417 			break;
418 
419 		default:
420 			retIntError();
421 		}
422 	if( cryptStatusError( status ) )
423 		return( status );
424 
425 	/* Skip any additional attribute information that may be present */
426 	if( stell( stream ) < endPos )
427 		{
428 		status = sseek( stream, endPos );
429 		if( cryptStatusError( status ) )
430 			return( status );
431 		}
432 
433 	return( isCryptlibObject ? OK_SPECIAL : CRYPT_OK );
434 	}
435 
436 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
readSubclassAttributes(INOUT STREAM * stream,INOUT PKCS15_INFO * pkcs15infoPtr,IN_ENUM (PKCS15_OBJECT)const PKCS15_OBJECT_TYPE type)437 static int readSubclassAttributes( INOUT STREAM *stream,
438 								   INOUT PKCS15_INFO *pkcs15infoPtr,
439 								   IN_ENUM( PKCS15_OBJECT ) \
440 										const PKCS15_OBJECT_TYPE type )
441 	{
442 	int tag, length, endPos, status;
443 
444 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
445 	assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
446 
447 	REQUIRES( type > PKCS15_OBJECT_NONE && type < PKCS15_OBJECT_LAST );
448 
449 	/* Read the attribute wrapper */
450 	readConstructed( stream, NULL, CTAG_OB_SUBCLASSATTR );
451 	status = readSequence( stream, &length );
452 	if( cryptStatusError( status ) )
453 		return( status );
454 	endPos = stell( stream ) + length;
455 	switch( type )
456 		{
457 		case PKCS15_OBJECT_PRIVKEY:
458 			if( checkStatusPeekTag( stream, status, tag ) && \
459 				tag == BER_SEQUENCE )						/* Name */
460 				status = readUniversal( stream );
461 			if( checkStatusLimitsPeekTag( stream, status, tag, endPos ) && \
462 				tag == MAKE_CTAG( CTAG_PK_IDENTIFIERS ) )	/* KeyIDs */
463 				{
464 				status = readConstructed( stream, &length,
465 										  CTAG_PK_IDENTIFIERS );
466 				if( cryptStatusOK( status ) && length > 0 )
467 					{
468 					status = readKeyIdentifiers( stream, pkcs15infoPtr,
469 												 stell( stream ) + length );
470 					}
471 				}
472 			break;
473 
474 		case PKCS15_OBJECT_PUBKEY:
475 		case PKCS15_OBJECT_CERT:
476 		case PKCS15_OBJECT_SECRETKEY:
477 		case PKCS15_OBJECT_DATA:
478 			/* These object types don't have subclass attributes */
479 			status = CRYPT_ERROR_BADDATA;
480 			break;
481 
482 		case PKCS15_OBJECT_UNRECOGNISED:
483 			/* It's an unrecognised object type, we don't know what to do
484 			   with any attributes that may be present */
485 			break;
486 
487 		default:
488 			retIntError();
489 		}
490 	if( cryptStatusError( status ) )
491 		return( status );
492 
493 	/* Skip any additional attribute information that may be present */
494 	if( stell( stream ) < endPos )
495 		{
496 		status = sseek( stream, endPos );
497 		if( cryptStatusError( status ) )
498 			return( status );
499 		}
500 
501 	return( CRYPT_OK );
502 	}
503 
504 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
readTypeAttributes(INOUT STREAM * stream,INOUT PKCS15_INFO * pkcs15infoPtr,IN_ENUM (PKCS15_OBJECT)const PKCS15_OBJECT_TYPE type,const BOOLEAN unrecognisedAttribute,const BOOLEAN isCryptlibData)505 static int readTypeAttributes( INOUT STREAM *stream,
506 							   INOUT PKCS15_INFO *pkcs15infoPtr,
507 							   IN_ENUM( PKCS15_OBJECT ) \
508 									const PKCS15_OBJECT_TYPE type,
509 							   const BOOLEAN unrecognisedAttribute,
510 							   const BOOLEAN isCryptlibData )
511 	{
512 	int tag, length, endPos, status;
513 
514 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
515 	assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
516 
517 	REQUIRES( type > PKCS15_OBJECT_NONE && type < PKCS15_OBJECT_LAST );
518 
519 	/* Read the attribute wrapper */
520 	readConstructed( stream, NULL, CTAG_OB_TYPEATTR );
521 	status = readSequence( stream, &length );
522 	if( cryptStatusError( status ) )
523 		return( status );
524 	endPos = stell( stream ) + length;
525 	if( unrecognisedAttribute )
526 		{
527 		/* It's a non-recognised object subtype, skip it */
528 		return( ( stell( stream ) < endPos ) ? \
529 				sseek( stream, endPos ) : CRYPT_OK );
530 		}
531 
532 	/* Parameterised types have special tagging requirements when using
533 	   context-specific tags and the declaration is a "Tag Type" (for
534 	   example for the "direct" choice for the ObjectValue type) and the
535 	   "Type" in the "Tag Type" is a "DummyReference".  In this case the
536 	   context tag is encoded as an EXPLICIT rather than IMPLCIIT tag (see
537 	   section F.2 of PKCS #15 v1.2 and newer).  The only case where this
538 	   occurs is for the ObjectValue.direct option.
539 
540 	   This is complicated by the fact that versions of PKCS #15 before v1.2
541 	   erroneously stated that all context-specific tags in parameterised
542 	   types should use EXPLICIT tagging, however no (known) implementation
543 	   ever did this.
544 
545 	   What this double error means is that existing implementations get
546 	   things almost right, the exception being ObjectValue.direct, which
547 	   does require an EXPLICIT tag.  To deal with this, we check for the
548 	   presence of the optional tag and skip it if it's present */
549 	if( checkStatusPeekTag( stream, status, tag ) && \
550 		tag == MAKE_CTAG( CTAG_OV_DIRECT ) )
551 		{
552 		status = readConstructed( stream, &length, CTAG_OV_DIRECT );
553 		}
554 	if( cryptStatusError( status ) )
555 		return( status );
556 
557 	/* Read the payload data, which just consists of remembering where the
558 	   payload starts */
559 	switch( type )
560 		{
561 		case PKCS15_OBJECT_PUBKEY:
562 			pkcs15infoPtr->pubKeyOffset = stell( stream );
563 			break;
564 
565 		case PKCS15_OBJECT_PRIVKEY:
566 			pkcs15infoPtr->privKeyOffset = stell( stream );
567 			break;
568 
569 		case PKCS15_OBJECT_CERT:
570 			pkcs15infoPtr->certOffset = stell( stream );
571 			break;
572 
573 		case PKCS15_OBJECT_SECRETKEY:
574 			pkcs15infoPtr->secretKeyOffset = stell( stream );
575 			break;
576 
577 		case PKCS15_OBJECT_DATA:
578 			{
579 			int value;
580 
581 			/* If it's not cryptlib data, we can't do much with it */
582 			if( !isCryptlibData )
583 				break;
584 
585 			/* It's a cryptlib data object, extract the contents */
586 			status = readOID( stream, cryptlibDataOIDinfo,
587 							  FAILSAFE_ARRAYSIZE( cryptlibDataOIDinfo, \
588 												  OID_INFO ),
589 							  &value );
590 			if( cryptStatusError( status ) )
591 				return( status );
592 			if( value == CRYPT_IATTRIBUTE_CONFIGDATA || \
593 				value == CRYPT_IATTRIBUTE_USERINDEX )
594 				{
595 				/* The configuration data and user index are SEQUENCEs of
596 				   objects */
597 				status = readSequence( stream, NULL );
598 				if( cryptStatusError( status ) )
599 					return( status );
600 				}
601 			if( value == CRYPT_ATTRIBUTE_NONE )
602 				{
603 				/* It's a non-recognised cryptlib data subtype, skip it */
604 				break;
605 				}
606 			pkcs15infoPtr->dataOffset = stell( stream );
607 			pkcs15infoPtr->dataType = value;
608 			break;
609 			}
610 
611 		default:
612 			retIntError();
613 		}
614 	if( cryptStatusError( status ) )
615 		return( status );
616 
617 	/* Skip the data payload */
618 	if( stell( stream ) < endPos )
619 		{
620 		status = sseek( stream, endPos );
621 		if( cryptStatusError( status ) )
622 			return( status );
623 		}
624 
625 	return( CRYPT_OK );
626 	}
627 
628 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
readObjectAttributes(INOUT STREAM * stream,INOUT PKCS15_INFO * pkcs15infoPtr,IN_ENUM (PKCS15_OBJECT)const PKCS15_OBJECT_TYPE type,INOUT ERROR_INFO * errorInfo)629 int readObjectAttributes( INOUT STREAM *stream,
630 						  INOUT PKCS15_INFO *pkcs15infoPtr,
631 						  IN_ENUM( PKCS15_OBJECT ) \
632 								const PKCS15_OBJECT_TYPE type,
633 						  INOUT ERROR_INFO *errorInfo )
634 	{
635 	const ALLOWED_ATTRIBUTE_TYPES *allowedTypeInfo;
636 	BOOLEAN skipDataRead = TRUE, isCryptlibData = FALSE;
637 	int tag, length, outerLength, lastTag = CRYPT_ERROR, i, status;
638 
639 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
640 	assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
641 
642 	REQUIRES( type > PKCS15_OBJECT_NONE && type < PKCS15_OBJECT_LAST );
643 	REQUIRES( errorInfo != NULL );
644 
645 	/* Clear the return value */
646 	memset( pkcs15infoPtr, 0, sizeof( PKCS15_INFO ) );
647 
648 	/* Find the allowed-subtype information for this object type */
649 	for( i = 0; \
650 		 allowedTypesTbl[ i ].type != type && \
651 			allowedTypesTbl[ i ].type != PKCS15_OBJECT_NONE && \
652 			i < FAILSAFE_ARRAYSIZE( allowedTypesTbl, ALLOWED_ATTRIBUTE_TYPES );
653 		 i++ );
654 	ENSURES( i < FAILSAFE_ARRAYSIZE( allowedTypesTbl, ALLOWED_ATTRIBUTE_TYPES ) );
655 	allowedTypeInfo = &allowedTypesTbl[ i ];
656 
657 	/* Make sure that this is a subtype that we can handle */
658 	status = tag = peekTag( stream );
659 	if( cryptStatusError( status ) )
660 		return( status );
661 	status = readGenericHole( stream, &outerLength, MIN_OBJECT_SIZE,
662 							  DEFAULT_TAG );
663 	if( cryptStatusError( status ) )
664 		return( status );
665 	for( i = 0; allowedTypeInfo->subTypes[ i ] != CRYPT_ERROR && \
666 				i < FAILSAFE_ITERATIONS_SMALL; i++ )
667 		{
668 		/* If this is a recognised subtype, process the attribute data */
669 		if( allowedTypeInfo->subTypes[ i ] == tag )
670 			{
671 			skipDataRead = FALSE;
672 			break;
673 			}
674 		lastTag = allowedTypeInfo->subTypes[ i ];
675 		}
676 	ENSURES( i < FAILSAFE_ITERATIONS_SMALL );
677 
678 	/* If this is an unrecognised subtype, make sure that it's at least
679 	   vaguely valid.  Tags are in the range { BER_SEQUENCE, [0]...[n] },
680 	   we interpret "vaguely valid" to mean within a short distance of the
681 	   last tag [n] that we recognise as valid */
682 	if( skipDataRead && ( tag != BER_SEQUENCE ) && \
683 		( tag < MAKE_CTAG( 0 ) || tag > lastTag + 10 ) )
684 		return( CRYPT_ERROR_BADDATA );
685 
686 	/* Process the PKCS15CommonObjectAttributes.  These may have zero length
687 	   so we use readSequenceZ() */
688 	status = readSequenceZ( stream, &length );
689 	if( cryptStatusOK( status ) && length > 0 )
690 		{
691 		const int endPos = stell( stream ) + length;
692 
693 		/* Read the label if it's present and skip anything else */
694 		if( checkStatusPeekTag( stream, status, tag ) && \
695 			tag == BER_STRING_UTF8 )
696 			{
697 			status = readCharacterString( stream,
698 						pkcs15infoPtr->label, CRYPT_MAX_TEXTSIZE,
699 						&pkcs15infoPtr->labelLength, BER_STRING_UTF8 );
700 			}
701 		if( !cryptStatusError( status ) && stell( stream ) < endPos )
702 			status = sseek( stream, endPos );
703 		}
704 	if( cryptStatusError( status ) )
705 		{
706 		retExt( status,
707 				( status, errorInfo,
708 				  "Invalid PKCS #15 common object attributes" ) );
709 		}
710 
711 	/* Process the class attributes */
712 	status = readClassAttributes( stream, pkcs15infoPtr, type );
713 	if( cryptStatusError( status ) && status != OK_SPECIAL )
714 		{
715 		retExt( status,
716 				( status, errorInfo,
717 				  "Invalid PKCS #15 %s attributes",
718 				  ( type == PKCS15_OBJECT_PUBKEY ) ? "public key" : \
719 				  ( type == PKCS15_OBJECT_PRIVKEY ) ? "private key" : \
720 				  ( type == PKCS15_OBJECT_CERT ) ? "certificate" : \
721 				  ( type == PKCS15_OBJECT_DATA ) ? "data object" : \
722 												   "class" ) );
723 		}
724 	if( status == OK_SPECIAL )
725 		isCryptlibData = TRUE;
726 
727 	/* We have to have at least an ID present for any standard object
728 	   types */
729 	ENSURES( ( type == PKCS15_OBJECT_SECRETKEY || \
730 			   type == PKCS15_OBJECT_DATA || \
731 			   type == PKCS15_OBJECT_UNRECOGNISED ) || \
732 			 pkcs15infoPtr->iDlength > 0 );
733 
734 	/* If there's no keyID present then we use the iD as the keyID */
735 	if( pkcs15infoPtr->keyIDlength <= 0 && pkcs15infoPtr->iDlength > 0 )
736 		{
737 		memcpy( pkcs15infoPtr->keyID, pkcs15infoPtr->iD,
738 				pkcs15infoPtr->iDlength );
739 		pkcs15infoPtr->keyIDlength = pkcs15infoPtr->iDlength;
740 		}
741 
742 	/* Skip the subclass attributes if present */
743 	if( checkStatusPeekTag( stream, status, tag ) && \
744 		tag == MAKE_CTAG( CTAG_OB_SUBCLASSATTR ) )
745 		{
746 		status = readSubclassAttributes( stream, pkcs15infoPtr, type );
747 		if( cryptStatusError( status ) )
748 			{
749 			retExt( status,
750 					( status, errorInfo,
751 					  "Invalid PKCS #15 %s attributes",
752 					  ( type == PKCS15_OBJECT_PRIVKEY ) ? "private key" : \
753 														  "subclass" ) );
754 			}
755 		}
756 
757 	/* Process the type attributes */
758 	status = readTypeAttributes( stream, pkcs15infoPtr, type,
759 								 skipDataRead, isCryptlibData );
760 	if( cryptStatusError( status ) )
761 		{
762 		retExt( status,
763 				( status, errorInfo,
764 				  "Invalid PKCS #15 %s payload data",
765 				  ( type == PKCS15_OBJECT_PUBKEY ) ? "public key" : \
766 				  ( type == PKCS15_OBJECT_PRIVKEY ) ? "private key" : \
767 				  ( type == PKCS15_OBJECT_CERT ) ? "certificate" : \
768 				  ( type == PKCS15_OBJECT_DATA ) ? "data object" : \
769 												   "class" ) );
770 		}
771 
772 	return( skipDataRead ? OK_SPECIAL : CRYPT_OK );
773 	}
774 #endif /* USE_PKCS15 */
775