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