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