1 /****************************************************************************
2 * *
3 * cryptlib PKCS #15 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 /* OID information used to read the header of a PKCS #15 keyset. Since the
25 PKCS #15 content can be further wrapped in CMS AuthData we have to check
26 for both types of content. If we find AuthData we retry the read, this
27 time allowing only PKCS #15 content. In addition since this is inner
28 content in an EncapsulatedContentInfo structure we don't specify any
29 version information because the additional OCTET STRING encapsulation
30 used with EncapsulatedContentInfo means that we need to dig down further
31 before we can find this field */
32
33 static const CMS_CONTENT_INFO FAR_BSS oidInfoPkcs15Data = { 0, 0 };
34
35 static const OID_INFO FAR_BSS keyFileOIDinfo[] = {
36 { OID_PKCS15_CONTENTTYPE, TRUE, &oidInfoPkcs15Data },
37 { OID_CMS_AUTHDATA, FALSE, &oidInfoPkcs15Data },
38 { NULL, 0 }, { NULL, 0 }
39 };
40 static const OID_INFO FAR_BSS keyFilePKCS15OIDinfo[] = {
41 { OID_PKCS15_CONTENTTYPE, CRYPT_OK, NULL },
42 { NULL, 0 }, { NULL, 0 }
43 };
44
45 /****************************************************************************
46 * *
47 * Utility Functions *
48 * *
49 ****************************************************************************/
50
51 /* Sanity-check the PKCS #15 information state */
52
53 CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
sanityCheck(const PKCS15_INFO * pkcs15infoPtr)54 static BOOLEAN sanityCheck( const PKCS15_INFO *pkcs15infoPtr )
55 {
56 assert( isReadPtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
57
58 /* Check that the basic fields are in order. The label field can be
59 empty for standalone certificates or public keys, which don't
60 usually have a label associated with the key */
61 if( pkcs15infoPtr->type <= PKCS15_SUBTYPE_NONE || \
62 pkcs15infoPtr->type >= PKCS15_SUBTYPE_LAST || \
63 pkcs15infoPtr->index < 0 || \
64 pkcs15infoPtr->index >= MAX_INTLENGTH )
65 return( FALSE );
66 if( pkcs15infoPtr->labelLength < 0 || \
67 pkcs15infoPtr->labelLength > CRYPT_MAX_TEXTSIZE )
68 return( FALSE );
69 if( pkcs15infoPtr->type == PKCS15_SUBTYPE_SECRETKEY || \
70 pkcs15infoPtr->type == PKCS15_SUBTYPE_DATA )
71 {
72 if( pkcs15infoPtr->iDlength != 0 || \
73 pkcs15infoPtr->keyIDlength != 0 )
74 return( FALSE );
75 }
76 else
77 {
78 if( pkcs15infoPtr->iDlength <= 0 || \
79 pkcs15infoPtr->iDlength > CRYPT_MAX_HASHSIZE || \
80 pkcs15infoPtr->keyIDlength <= 0 || \
81 pkcs15infoPtr->keyIDlength > CRYPT_MAX_HASHSIZE )
82 return( FALSE );
83 }
84
85 /* Check that the ID fields have reasonable values. This is a general
86 check for reasonable values that's more targeted at catching
87 inadvertent memory corruption than a strict sanity check */
88 if( pkcs15infoPtr->iAndSIDlength < 0 || \
89 pkcs15infoPtr->iAndSIDlength > KEYID_SIZE || \
90 pkcs15infoPtr->subjectNameIDlength < 0 || \
91 pkcs15infoPtr->subjectNameIDlength > KEYID_SIZE || \
92 pkcs15infoPtr->issuerNameIDlength < 0 || \
93 pkcs15infoPtr->issuerNameIDlength > KEYID_SIZE )
94 return( FALSE );
95 if( pkcs15infoPtr->pgp2KeyIDlength < 0 || \
96 pkcs15infoPtr->pgp2KeyIDlength > PGP_KEYID_SIZE || \
97 pkcs15infoPtr->openPGPKeyIDlength < 0 || \
98 pkcs15infoPtr->openPGPKeyIDlength > PGP_KEYID_SIZE )
99 return( FALSE );
100
101 /* Check that the key/certificate data fields have reasonable values.
102 This is a general check for reasonable values that's more targeted
103 at catching inadvertent memory corruption than a strict sanity
104 check */
105 if( pkcs15infoPtr->pubKeyData != NULL )
106 {
107 if( pkcs15infoPtr->pubKeyDataSize <= 0 || \
108 pkcs15infoPtr->pubKeyDataSize > MAX_INTLENGTH_SHORT || \
109 pkcs15infoPtr->pubKeyOffset <= 0 || \
110 pkcs15infoPtr->pubKeyOffset >= pkcs15infoPtr->pubKeyDataSize )
111 return( FALSE );
112 }
113 else
114 {
115 if( pkcs15infoPtr->pubKeyDataSize != 0 || \
116 pkcs15infoPtr->pubKeyOffset != 0 )
117 return( FALSE );
118 }
119 if( pkcs15infoPtr->privKeyData != NULL )
120 {
121 if( pkcs15infoPtr->privKeyDataSize <= 0 || \
122 pkcs15infoPtr->privKeyDataSize > MAX_INTLENGTH_SHORT || \
123 pkcs15infoPtr->privKeyOffset <= 0 || \
124 pkcs15infoPtr->privKeyOffset >= pkcs15infoPtr->privKeyDataSize )
125 return( FALSE );
126 }
127 else
128 {
129 if( pkcs15infoPtr->privKeyDataSize != 0 || \
130 pkcs15infoPtr->privKeyOffset != 0 )
131 return( FALSE );
132 }
133 if( pkcs15infoPtr->certData != NULL )
134 {
135 if( pkcs15infoPtr->certDataSize <= 0 || \
136 pkcs15infoPtr->certDataSize > MAX_INTLENGTH_SHORT || \
137 pkcs15infoPtr->certOffset <= 0 || \
138 pkcs15infoPtr->certOffset >= pkcs15infoPtr->certDataSize )
139 return( FALSE );
140 }
141 else
142 {
143 if( pkcs15infoPtr->certDataSize != 0 || \
144 pkcs15infoPtr->certOffset != 0 )
145 return( FALSE );
146 }
147
148 return( TRUE );
149 }
150
151 /* Get the hash of various certificate name fields */
152
153 CHECK_RETVAL STDC_NONNULL_ARG( ( 3, 5 ) ) \
getCertID(IN_HANDLE const CRYPT_HANDLE iCryptHandle,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE nameType,OUT_BUFFER (nameIdMaxLen,* nameIdLen)BYTE * nameID,IN_LENGTH_SHORT_MIN (KEYID_SIZE)const int nameIdMaxLen,OUT_LENGTH_BOUNDED_Z (nameIdMaxLen)int * nameIdLen)154 int getCertID( IN_HANDLE const CRYPT_HANDLE iCryptHandle,
155 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE nameType,
156 OUT_BUFFER( nameIdMaxLen, *nameIdLen ) BYTE *nameID,
157 IN_LENGTH_SHORT_MIN( KEYID_SIZE ) const int nameIdMaxLen,
158 OUT_LENGTH_BOUNDED_Z( nameIdMaxLen ) int *nameIdLen )
159 {
160 HASH_FUNCTION_ATOMIC hashFunctionAtomic;
161 DYNBUF idDB;
162 int status;
163
164 assert( isWritePtr( nameID, nameIdMaxLen ) );
165 assert( isWritePtr( nameIdLen, sizeof( int ) ) );
166
167 REQUIRES( isHandleRangeValid( iCryptHandle ) );
168 REQUIRES( nameType == CRYPT_IATTRIBUTE_SPKI || \
169 nameType == CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER || \
170 nameType == CRYPT_IATTRIBUTE_SUBJECT || \
171 nameType == CRYPT_IATTRIBUTE_ISSUER );
172 REQUIRES( nameIdMaxLen >= KEYID_SIZE && \
173 nameIdMaxLen < MAX_INTLENGTH_SHORT );
174
175 /* Clear return value */
176 *nameIdLen = 0;
177
178 /* Get the attribute data and hash algorithm information and hash the
179 attribute to get the ID */
180 status = dynCreate( &idDB, iCryptHandle, nameType );
181 if( cryptStatusError( status ) )
182 return( status );
183 getHashAtomicParameters( CRYPT_ALGO_SHA1, 0, &hashFunctionAtomic, NULL );
184 hashFunctionAtomic( nameID, nameIdMaxLen, dynData( idDB ),
185 dynLength( idDB ) );
186 dynDestroy( &idDB );
187 *nameIdLen = nameIdMaxLen;
188
189 return( CRYPT_OK );
190 }
191
192 /* Locate a PKCS #15 object based on an ID */
193
194 #define matchID( src, srcLen, dest, destLen ) \
195 ( ( srcLen ) > 0 && ( srcLen ) == ( destLen ) && \
196 !memcmp( ( src ), ( dest ), ( destLen ) ) )
197
198 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1 ) ) \
findEntry(IN_ARRAY (noPkcs15objects)const PKCS15_INFO * pkcs15info,IN_LENGTH_SHORT const int noPkcs15objects,IN_KEYID_OPT const CRYPT_KEYID_TYPE keyIDtype,IN_BUFFER_OPT (keyIDlength)const void * keyID,IN_LENGTH_KEYID_Z const int keyIDlength,IN_FLAGS_Z (KEYMGMT)const int requestedUsage,const BOOLEAN isWildcardMatch)199 PKCS15_INFO *findEntry( IN_ARRAY( noPkcs15objects ) const PKCS15_INFO *pkcs15info,
200 IN_LENGTH_SHORT const int noPkcs15objects,
201 IN_KEYID_OPT const CRYPT_KEYID_TYPE keyIDtype,
202 /* CRYPT_KEYIDEX_ID maps to CRYPT_KEYID_NONE */
203 IN_BUFFER_OPT( keyIDlength ) const void *keyID,
204 IN_LENGTH_KEYID_Z const int keyIDlength,
205 IN_FLAGS_Z( KEYMGMT ) const int requestedUsage,
206 const BOOLEAN isWildcardMatch )
207 {
208 int i;
209
210 assert( isReadPtr( pkcs15info, \
211 sizeof( PKCS15_INFO ) * noPkcs15objects ) );
212 assert( ( keyID == NULL && keyIDlength == 0 ) || \
213 isReadPtr( keyID, keyIDlength ) );
214
215 REQUIRES_N( noPkcs15objects >= 1 && \
216 noPkcs15objects < MAX_INTLENGTH_SHORT );
217 REQUIRES_N( keyIDtype == CRYPT_KEYID_NAME || \
218 keyIDtype == CRYPT_KEYID_URI || \
219 keyIDtype == CRYPT_IKEYID_KEYID || \
220 keyIDtype == CRYPT_IKEYID_PGPKEYID || \
221 keyIDtype == CRYPT_IKEYID_SUBJECTID || \
222 keyIDtype == CRYPT_IKEYID_ISSUERID || \
223 keyIDtype == CRYPT_KEYIDEX_ID );
224 REQUIRES_N( ( keyID == NULL && keyIDlength == 0 ) || \
225 ( keyID != NULL && \
226 keyIDlength >= MIN_NAME_LENGTH && \
227 keyIDlength < MAX_ATTRIBUTE_SIZE ) );
228 REQUIRES_N( requestedUsage >= KEYMGMT_FLAG_NONE && \
229 requestedUsage < KEYMGMT_FLAG_MAX );
230 REQUIRES_N( ( requestedUsage & KEYMGMT_MASK_USAGEOPTIONS ) != \
231 KEYMGMT_MASK_USAGEOPTIONS );
232 REQUIRES_N( ( isWildcardMatch && keyID == NULL ) || !isWildcardMatch );
233
234 /* If there's no ID to search on and we're not performing a wildcard
235 match, don't try and do anything. This can occur when we're trying
236 to build a chain and the necessary chaining data like an issuerID
237 isn't present in the keyset */
238 if( ( keyID == NULL || keyIDlength <= 0 ) && !isWildcardMatch )
239 return( NULL );
240
241 /* Try and locate the appropriate object in the PKCS #15 collection */
242 for( i = 0; i < noPkcs15objects && i < FAILSAFE_ITERATIONS_MED; i++ )
243 {
244 const PKCS15_INFO *pkcs15infoPtr = &pkcs15info[ i ];
245 const int compositeUsage = pkcs15infoPtr->pubKeyUsage | \
246 pkcs15infoPtr->privKeyUsage;
247
248 /* If there's no entry at this position, continue */
249 if( pkcs15infoPtr->type == PKCS15_SUBTYPE_NONE )
250 continue;
251
252 ENSURES_N( sanityCheck( pkcs15infoPtr ) );
253
254 /* If there's an explicit usage requested, make sure that the key
255 usage matches this. This can get slightly complex because the
256 advertised usage isn't necessarily the same as the usage
257 permitted by the associated certificate (PKCS #11 apps are
258 particularly good at setting bogus usage types) and the overall
259 result can be further influenced by trusted usage settings, so
260 all that we check for here is an indicated usage for the key
261 matching the requested usage */
262 if( ( requestedUsage & KEYMGMT_FLAG_USAGE_CRYPT ) && \
263 !( compositeUsage & ENCR_USAGE_MASK ) )
264 continue;
265 if( ( requestedUsage & KEYMGMT_FLAG_USAGE_SIGN ) && \
266 !( compositeUsage & SIGN_USAGE_MASK ) )
267 continue;
268
269 /* If we're performing a wildcard match, return the first private-key
270 entry. In theory this shouldn't be necessary since cryptlib-
271 generated keysets must have valid labels, but keysets from other
272 implementations may not have them, or may have machine-generated
273 labels that don't work well for human use, so we allow a wildcard
274 match as a generic "get me whatever you can" */
275 if( isWildcardMatch )
276 {
277 if( pkcs15infoPtr->privKeyData == NULL )
278 continue; /* No private-key data present, continue */
279 return( ( PKCS15_INFO * ) pkcs15infoPtr );
280 }
281
282 /* Check for a match based on the ID type */
283 switch( keyIDtype )
284 {
285 case CRYPT_KEYID_NAME:
286 case CRYPT_KEYID_URI:
287 if( matchID( pkcs15infoPtr->label, pkcs15infoPtr->labelLength,
288 keyID, keyIDlength ) )
289 return( ( PKCS15_INFO * ) pkcs15infoPtr );
290 break;
291
292 case CRYPT_IKEYID_KEYID:
293 if( matchID( pkcs15infoPtr->keyID, pkcs15infoPtr->keyIDlength,
294 keyID, keyIDlength ) )
295 return( ( PKCS15_INFO * ) pkcs15infoPtr );
296 break;
297
298 case CRYPT_IKEYID_PGPKEYID:
299 /* For the PGP keyID we compare both IDs for the reasons
300 given in the PGP keyset read code */
301 if( matchID( pkcs15infoPtr->pgp2KeyID,
302 pkcs15infoPtr->pgp2KeyIDlength, keyID,
303 keyIDlength ) || \
304 matchID( pkcs15infoPtr->openPGPKeyID,
305 pkcs15infoPtr->openPGPKeyIDlength, keyID,
306 keyIDlength ) )
307 return( ( PKCS15_INFO * ) pkcs15infoPtr );
308 break;
309
310 case CRYPT_IKEYID_SUBJECTID:
311 if( matchID( pkcs15infoPtr->subjectNameID,
312 pkcs15infoPtr->subjectNameIDlength, keyID,
313 keyIDlength ) )
314 return( ( PKCS15_INFO * ) pkcs15infoPtr );
315 break;
316
317 case CRYPT_IKEYID_ISSUERID:
318 if( matchID( pkcs15infoPtr->iAndSID,
319 pkcs15infoPtr->iAndSIDlength, keyID,
320 keyIDlength ) )
321 return( ( PKCS15_INFO * ) pkcs15infoPtr );
322 break;
323
324 case CRYPT_KEYIDEX_ID:
325 if( matchID( pkcs15infoPtr->iD, pkcs15infoPtr->iDlength,
326 keyID, keyIDlength ) )
327 return( ( PKCS15_INFO * ) pkcs15infoPtr );
328 break;
329
330 default:
331 retIntError_Null();
332 }
333 }
334 ENSURES_N( i < FAILSAFE_ITERATIONS_MED );
335
336 /* If we're trying to match on the PGP key ID and didn't find anything,
337 retry it using the first PGP_KEYID_SIZE bytes of the object ID. This
338 is necessary because calculation of the OpenPGP ID requires the
339 presence of data that may not be present in non-PGP keys so we can't
340 calculate a real OpenPGP ID but have to use the next-best thing
341 (sol lucet omnibus) */
342 if( keyIDtype == CRYPT_IKEYID_PGPKEYID )
343 {
344 for( i = 0; i < noPkcs15objects && i < FAILSAFE_ITERATIONS_MED; i++ )
345 {
346 const PKCS15_INFO *pkcs15infoPtr = &pkcs15info[ i ];
347
348 if( pkcs15infoPtr->type != PKCS15_SUBTYPE_NONE && \
349 pkcs15infoPtr->iDlength >= PGP_KEYID_SIZE && \
350 !memcmp( keyID, pkcs15infoPtr->iD, PGP_KEYID_SIZE ) )
351 return( ( PKCS15_INFO * ) pkcs15infoPtr );
352 }
353 ENSURES_N( i < FAILSAFE_ITERATIONS_MED );
354 }
355
356 return( NULL );
357 }
358
359 /* Find a free PKCS #15 entry */
360
361 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1 ) ) \
findFreeEntry(IN_ARRAY (noPkcs15objects)const PKCS15_INFO * pkcs15info,IN_LENGTH_SHORT const int noPkcs15objects,OUT_OPT_INDEX (noPkcs15objects)int * index)362 PKCS15_INFO *findFreeEntry( IN_ARRAY( noPkcs15objects ) \
363 const PKCS15_INFO *pkcs15info,
364 IN_LENGTH_SHORT const int noPkcs15objects,
365 OUT_OPT_INDEX( noPkcs15objects ) int *index )
366 {
367 int i;
368
369 assert( isReadPtr( pkcs15info, \
370 sizeof( PKCS15_INFO ) * noPkcs15objects ) );
371 assert( ( index == NULL ) || isWritePtr( index, sizeof( int ) ) );
372
373 REQUIRES_N( noPkcs15objects >= 1 && \
374 noPkcs15objects < MAX_INTLENGTH_SHORT );
375
376 /* Clear return value */
377 if( index != NULL )
378 *index = CRYPT_ERROR;
379
380 for( i = 0; i < noPkcs15objects && i < FAILSAFE_ITERATIONS_MED; i++ )
381 {
382 if( pkcs15info[ i ].type == PKCS15_SUBTYPE_NONE )
383 break;
384 }
385 ENSURES_N( i < FAILSAFE_ITERATIONS_MED );
386 if( i >= noPkcs15objects )
387 return( NULL );
388
389 /* Remember the index value (used for enumerating PKCS #15 entries) for
390 this entry if required */
391 if( index != NULL )
392 *index = i;
393
394 return( ( PKCS15_INFO * ) &pkcs15info[ i ] );
395 }
396
397 /* Free object entries */
398
399 STDC_NONNULL_ARG( ( 1 ) ) \
pkcs15freeEntry(INOUT PKCS15_INFO * pkcs15info)400 void pkcs15freeEntry( INOUT PKCS15_INFO *pkcs15info )
401 {
402 assert( isWritePtr( pkcs15info, sizeof( PKCS15_INFO ) ) );
403
404 if( pkcs15info->pubKeyData != NULL )
405 {
406 zeroise( pkcs15info->pubKeyData, pkcs15info->pubKeyDataSize );
407 clFree( "pkcs15freeEntry", pkcs15info->pubKeyData );
408 }
409 if( pkcs15info->privKeyData != NULL )
410 {
411 zeroise( pkcs15info->privKeyData, pkcs15info->privKeyDataSize );
412 clFree( "pkcs15freeEntry", pkcs15info->privKeyData );
413 }
414 if( pkcs15info->certData != NULL )
415 {
416 zeroise( pkcs15info->certData, pkcs15info->certDataSize );
417 clFree( "pkcs15freeEntry", pkcs15info->certData );
418 }
419 if( pkcs15info->dataData != NULL )
420 {
421 zeroise( pkcs15info->dataData, pkcs15info->dataDataSize );
422 clFree( "pkcs15freeEntry", pkcs15info->dataData );
423 }
424 zeroise( pkcs15info, sizeof( PKCS15_INFO ) );
425 }
426
427 STDC_NONNULL_ARG( ( 1 ) ) \
INOUT_ARRAY(noPkcs15objects)428 void pkcs15Free( INOUT_ARRAY( noPkcs15objects ) PKCS15_INFO *pkcs15info,
429 IN_RANGE( 1, MAX_PKCS15_OBJECTS ) const int noPkcs15objects )
430 {
431 int i;
432
433 assert( isWritePtr( pkcs15info, \
434 sizeof( PKCS15_INFO ) * noPkcs15objects ) );
435
436 REQUIRES_V( noPkcs15objects >= 1 && \
437 noPkcs15objects <= MAX_PKCS15_OBJECTS );
438
439 for( i = 0; i < noPkcs15objects && i < FAILSAFE_ITERATIONS_MED; i++ )
440 pkcs15freeEntry( &pkcs15info[ i ] );
441 ENSURES_V( i < FAILSAFE_ITERATIONS_MED );
442 zeroise( pkcs15info, sizeof( PKCS15_INFO ) * noPkcs15objects );
443 }
444
445 /* Get the PKCS #15 validity information from a certificate */
446
447 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
getValidityInfo(INOUT PKCS15_INFO * pkcs15info,IN_HANDLE const CRYPT_HANDLE cryptHandle)448 int getValidityInfo( INOUT PKCS15_INFO *pkcs15info,
449 IN_HANDLE const CRYPT_HANDLE cryptHandle )
450 {
451 MESSAGE_DATA msgData;
452 time_t validFrom, validTo;
453 int status;
454
455 assert( isWritePtr( pkcs15info, sizeof( PKCS15_INFO ) ) );
456
457 REQUIRES( isHandleRangeValid( cryptHandle ) );
458
459 /* Remember the validity information for later. We always update the
460 validity (even if it's already set) since we may be replacing an
461 older certificate with a newer one */
462 setMessageData( &msgData, &validFrom, sizeof( time_t ) );
463 status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
464 &msgData, CRYPT_CERTINFO_VALIDFROM );
465 if( cryptStatusError( status ) )
466 return( status );
467 setMessageData( &msgData, &validTo, sizeof( time_t ) );
468 status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
469 &msgData, CRYPT_CERTINFO_VALIDTO );
470 if( cryptStatusError( status ) )
471 return( status );
472 if( pkcs15info->validTo > validTo )
473 {
474 /* There's an existing, newer certificate already present, make sure
475 that we don't try and add the new one */
476 return( CRYPT_ERROR_DUPLICATE );
477 }
478 pkcs15info->validFrom = validFrom;
479 pkcs15info->validTo = validTo;
480
481 return( CRYPT_OK );
482 }
483
484 /* Read the header of a PKCS #15 keyset */
485
486 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
readPkcs15EncapsHeader(INOUT STREAM * stream,OUT long * endPosPtr)487 static int readPkcs15EncapsHeader( INOUT STREAM *stream,
488 OUT long *endPosPtr )
489 {
490 long length;
491 int tag, innerLength, status;
492
493 assert( isWritePtr( stream, sizeof( STREAM ) ) );
494 assert( isWritePtr( endPosPtr, sizeof( long ) ) );
495
496 /* Clear return value */
497 *endPosPtr = 0;
498
499 /* The outer header was a CMS AuthData wrapper, try again for an inner
500 PKCS #15 header. First we skip the AuthData SET OF RECIPIENTINFO,
501 macAlgorithm AlgorithmIdentifier, and optional digestAlgorithm
502 AlgorithmIdentifier */
503 readUniversal( stream );
504 status = readUniversal( stream );
505 if( checkStatusPeekTag( stream, status, tag ) && \
506 tag == MAKE_CTAG( 1 ) )
507 status = readUniversal( stream );
508 if( cryptStatusError( status ) )
509 return( status );
510
511 /* We've made our way past the AuthData information, try again for
512 encapsulated PKCS #15 content */
513 status = readCMSheader( stream, keyFilePKCS15OIDinfo,
514 FAILSAFE_ARRAYSIZE( keyFilePKCS15OIDinfo, OID_INFO ),
515 &length, READCMS_FLAG_INNERHEADER );
516 if( cryptStatusError( status ) )
517 return( status );
518
519 /* Since this is EncapsulatedContentInfo the version information doesn't
520 immediately follow the header but is encapsulated inside an OCTET
521 STRING, so we have to skip an additional layer of wrapping and
522 manually read the version information. In addition the OCTET STRING
523 could be indefinite-length, in which case it acts as a constructed
524 value containing an inner OCTET STRING, so we have to skip the inner
525 OCTET STRING before we get to the actual content */
526 if( length == CRYPT_UNUSED )
527 {
528 /* It's an indefinite-length OCTET STRING, skip the inner OCTET
529 STRING wrapper */
530 readOctetStringHole( stream, NULL, 16, DEFAULT_TAG );
531 }
532 status = readSequence( stream, &innerLength );
533 if( cryptStatusOK( status ) )
534 {
535 long value;
536
537 *endPosPtr = innerLength;
538 status = readShortInteger( stream, &value );
539 if( cryptStatusOK( status ) && value != 0 )
540 status = CRYPT_ERROR_BADDATA;
541 }
542
543 return( status );
544 }
545
546 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
readPkcs15header(INOUT STREAM * stream,OUT_INT_Z long * endPosPtr,INOUT ERROR_INFO * errorInfo)547 static int readPkcs15header( INOUT STREAM *stream,
548 OUT_INT_Z long *endPosPtr,
549 INOUT ERROR_INFO *errorInfo )
550 {
551 long endPos, currentPos;
552 int value, status;
553
554 assert( isWritePtr( stream, sizeof( STREAM ) ) );
555 assert( isWritePtr( endPosPtr, sizeof( long ) ) );
556 assert( isWritePtr( errorInfo, sizeof( ERROR_INFO ) ) );
557
558 /* Clear return value */
559 *endPosPtr = 0;
560
561 /* Read the outer header and make sure that the length information is
562 valid */
563 status = value = readCMSheader( stream, keyFileOIDinfo,
564 FAILSAFE_ARRAYSIZE( keyFileOIDinfo, OID_INFO ),
565 &endPos, READCMS_FLAG_DEFINITELENGTH_OPT );
566 if( cryptStatusError( status ) )
567 {
568 retExt( CRYPT_ERROR_BADDATA,
569 ( CRYPT_ERROR_BADDATA, errorInfo,
570 "Invalid PKCS #15 keyset header" ) );
571 }
572 if( value == FALSE )
573 {
574 /* The outer header was a CMS AuthData wrapper, try again for an
575 inner PKCS #15 header */
576 status = readPkcs15EncapsHeader( stream, &endPos );
577 if( cryptStatusError( status ) )
578 {
579 retExt( CRYPT_ERROR_BADDATA,
580 ( CRYPT_ERROR_BADDATA, errorInfo,
581 "Invalid PKCS #15 content wrapped in AuthData" ) );
582 }
583 }
584
585 /* If it's indefinite-length data, don't try and go any further (the
586 general length check below will also catch this, but we make the
587 check explicit here) */
588 if( endPos == CRYPT_UNUSED )
589 {
590 retExt( CRYPT_ERROR_BADDATA,
591 ( CRYPT_ERROR_BADDATA, errorInfo,
592 "Can't process indefinite-length PKCS #15 content" ) );
593 }
594
595 /* Make sure that the length information is sensible. readCMSheader()
596 reads the version number field at the start of the content so we have
597 to adjust the stream position for this when we calculate the data end
598 position */
599 currentPos = stell( stream ) - sizeofShortInteger( 0 );
600 if( endPos < 16 + MIN_OBJECT_SIZE || \
601 currentPos + endPos >= MAX_BUFFER_SIZE )
602 {
603 retExt( CRYPT_ERROR_BADDATA,
604 ( CRYPT_ERROR_BADDATA, errorInfo,
605 "Invalid PKCS #15 keyset length information" ) );
606 }
607 *endPosPtr = currentPos + endPos;
608
609 /* Skip the key management information if there is any and read the
610 inner wrapper */
611 if( checkStatusPeekTag( stream, status, value ) && \
612 value == MAKE_CTAG( 0 ) )
613 {
614 status = readUniversal( stream );
615 if( cryptStatusError( status ) )
616 return( status );
617 }
618 status = readLongSequence( stream, NULL );
619 if( cryptStatusError( status ) )
620 return( status );
621
622 /* Make sure that, after skipping the key management data, there's still
623 some payload left */
624 if( stell( stream ) >= endPos - MIN_OBJECT_SIZE )
625 return( CRYPT_ERROR_BADDATA );
626
627 return( CRYPT_OK );
628 }
629
630 /****************************************************************************
631 * *
632 * Init/Shutdown Functions *
633 * *
634 ****************************************************************************/
635
636 /* A PKCS #15 keyset can contain multiple keys and whatnot, so when we open
637 it we parse the contents into memory for later use */
638
639 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
initFunction(INOUT KEYSET_INFO * keysetInfoPtr,STDC_UNUSED const char * name,STDC_UNUSED const int nameLength,IN_ENUM (CRYPT_KEYOPT)const CRYPT_KEYOPT_TYPE options)640 static int initFunction( INOUT KEYSET_INFO *keysetInfoPtr,
641 STDC_UNUSED const char *name,
642 STDC_UNUSED const int nameLength,
643 IN_ENUM( CRYPT_KEYOPT ) const CRYPT_KEYOPT_TYPE options )
644 {
645 PKCS15_INFO *pkcs15info;
646 STREAM *stream = &keysetInfoPtr->keysetFile->stream;
647 long endPos DUMMY_INIT;
648 int status;
649
650 assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
651
652 REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
653 keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS15 );
654 REQUIRES( name == NULL && nameLength == 0 );
655 REQUIRES( options >= CRYPT_KEYOPT_NONE && options < CRYPT_KEYOPT_LAST );
656
657 /* If we're opening an existing keyset skip the outer header, optional
658 keyManagementInfo, and inner header. We do this before we perform any
659 setup operations to weed out potential problem keysets */
660 if( options != CRYPT_KEYOPT_CREATE )
661 {
662 status = readPkcs15header( stream, &endPos, KEYSET_ERRINFO );
663 if( cryptStatusError( status ) )
664 return( status );
665 }
666
667 /* Allocate the PKCS #15 object information */
668 if( ( pkcs15info = clAlloc( "initFunction", \
669 sizeof( PKCS15_INFO ) * \
670 MAX_PKCS15_OBJECTS ) ) == NULL )
671 {
672 if( options != CRYPT_KEYOPT_CREATE )
673 {
674 /* Reset the stream position to account for the header
675 information that we've already read */
676 sseek( stream, 0 ) ;
677 }
678 return( CRYPT_ERROR_MEMORY );
679 }
680 memset( pkcs15info, 0, sizeof( PKCS15_INFO ) * MAX_PKCS15_OBJECTS );
681 keysetInfoPtr->keyData = pkcs15info;
682 keysetInfoPtr->keyDataSize = sizeof( PKCS15_INFO ) * MAX_PKCS15_OBJECTS;
683 keysetInfoPtr->keyDataNoObjects = MAX_PKCS15_OBJECTS;
684
685 /* If this is a newly-created keyset, there's nothing left to do */
686 if( options == CRYPT_KEYOPT_CREATE )
687 return( CRYPT_OK );
688
689 /* Read all of the keys in the keyset */
690 status = readPkcs15Keyset( &keysetInfoPtr->keysetFile->stream,
691 pkcs15info, MAX_PKCS15_OBJECTS, endPos,
692 KEYSET_ERRINFO );
693 if( cryptStatusError( status ) )
694 {
695 clFree( "initFunction", keysetInfoPtr->keyData );
696 keysetInfoPtr->keyData = NULL;
697 keysetInfoPtr->keyDataSize = 0;
698 if( options != CRYPT_KEYOPT_CREATE )
699 {
700 /* Reset the stream position to account for the header
701 information that we've already read */
702 sseek( stream, 0 ) ;
703 }
704 return( status );
705 }
706
707 return( CRYPT_OK );
708 }
709
710 /* Shut down the PKCS #15 state, flushing information to disk if necessary */
711
712 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
shutdownFunction(INOUT KEYSET_INFO * keysetInfoPtr)713 static int shutdownFunction( INOUT KEYSET_INFO *keysetInfoPtr )
714 {
715 int status = CRYPT_OK;
716
717 assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
718
719 REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
720 keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS15 );
721
722 /* If the contents have been changed, allocate a working I/O buffer for
723 the duration of the flush and commit the changes to disk */
724 if( keysetInfoPtr->flags & KEYSET_DIRTY )
725 {
726 STREAM *stream = &keysetInfoPtr->keysetFile->stream;
727 BYTE buffer[ STREAM_BUFSIZE + 8 ];
728
729 sseek( stream, 0 );
730 memset( buffer, 0, STREAM_BUFSIZE );
731 /* Keep static analysers happy */
732 sioctlSetString( stream, STREAM_IOCTL_IOBUFFER, buffer,
733 STREAM_BUFSIZE );
734 status = pkcs15Flush( stream, keysetInfoPtr->keyData,
735 keysetInfoPtr->keyDataNoObjects );
736 sioctlSet( stream, STREAM_IOCTL_IOBUFFER, 0 );
737 if( status == OK_SPECIAL )
738 {
739 keysetInfoPtr->flags |= KEYSET_EMPTY;
740 status = CRYPT_OK;
741 }
742 }
743
744 /* Free the PKCS #15 object information */
745 if( keysetInfoPtr->keyData != NULL )
746 {
747 pkcs15Free( keysetInfoPtr->keyData, keysetInfoPtr->keyDataNoObjects );
748 zeroise( keysetInfoPtr->keyData, keysetInfoPtr->keyDataSize );
749 clFree( "shutdownFunction", keysetInfoPtr->keyData );
750 }
751
752 if( cryptStatusError( status ) )
753 {
754 retExt( status,
755 ( status, KEYSET_ERRINFO,
756 "Couldn't send PKCS #15 data to persistent storage" ) );
757 }
758
759 return( CRYPT_OK );
760 }
761
762 /****************************************************************************
763 * *
764 * Keyset Access Routines *
765 * *
766 ****************************************************************************/
767
768 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
setAccessMethodPKCS15(INOUT KEYSET_INFO * keysetInfoPtr)769 int setAccessMethodPKCS15( INOUT KEYSET_INFO *keysetInfoPtr )
770 {
771 int status;
772
773 assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
774
775 REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
776 keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS15 );
777
778 /* Set the access method pointers */
779 FNPTR_SET( keysetInfoPtr->initFunction, initFunction );
780 FNPTR_SET( keysetInfoPtr->shutdownFunction, shutdownFunction );
781 status = initPKCS15get( keysetInfoPtr );
782 if( cryptStatusOK( status ) )
783 status = initPKCS15set( keysetInfoPtr );
784 return( status );
785 }
786 #endif /* USE_PKCS15 */
787