1 /****************************************************************************
2 * *
3 * cryptlib PKCS #12 Routines *
4 * Copyright Peter Gutmann 1997-2010 *
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 "pkcs12.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/pkcs12.h"
20 #endif /* Compiler-specific includes */
21
22 #ifdef USE_PKCS12
23
24 /* OID information used to read the header of a PKCS #12 keyset */
25
26 static const CMS_CONTENT_INFO FAR_BSS oidInfoEncryptedData = { 0, 2 };
27
28 static const FAR_BSS OID_INFO dataOIDinfo[] = {
29 { OID_CMS_DATA, CRYPT_OK },
30 { NULL, 0 }, { NULL, 0 }
31 };
32
33 /****************************************************************************
34 * *
35 * Utility Functions *
36 * *
37 ****************************************************************************/
38
39 /* Sanity-check the PKCS #12 information state */
40
41 CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
sanityCheck(const PKCS12_INFO * pkcs12infoPtr)42 static BOOLEAN sanityCheck( const PKCS12_INFO *pkcs12infoPtr )
43 {
44 const PKCS12_OBJECT_INFO *objectInfoPtr;
45
46 assert( isReadPtr( pkcs12infoPtr, sizeof( PKCS12_INFO ) ) );
47
48 /* Check that the basic fields are in order. Since all of the fields are
49 optional, either of them may not be present */
50 if( pkcs12infoPtr->labelLength == 0 )
51 {
52 /* No label, there must be an ID present */
53 if( pkcs12infoPtr->idLength < 0 || \
54 pkcs12infoPtr->idLength > CRYPT_MAX_HASHSIZE )
55 return( FALSE );
56 }
57 else
58 {
59 /* There's a label, the ID is optional */
60 if( pkcs12infoPtr->labelLength <= 0 || \
61 pkcs12infoPtr->labelLength > CRYPT_MAX_TEXTSIZE || \
62 pkcs12infoPtr->idLength < 0 || \
63 pkcs12infoPtr->idLength > CRYPT_MAX_HASHSIZE )
64 return( FALSE );
65 }
66
67 /* Check that the object-specific fields have reasonable values. This
68 is a general check for reasonable values that's more targeted at
69 catching inadvertent memory corruption than a strict sanity check */
70 objectInfoPtr = &pkcs12infoPtr->keyInfo;
71 if( objectInfoPtr->data != NULL )
72 {
73 if( objectInfoPtr->dataSize <= 0 || \
74 objectInfoPtr->dataSize > MAX_INTLENGTH_SHORT || \
75 objectInfoPtr->payloadOffset <= 0 || \
76 objectInfoPtr->payloadOffset >= objectInfoPtr->dataSize || \
77 objectInfoPtr->payloadSize <= 0 || \
78 objectInfoPtr->payloadSize >= objectInfoPtr->dataSize )
79 return( FALSE );
80 }
81 else
82 {
83 if( objectInfoPtr->dataSize != 0 || \
84 objectInfoPtr->payloadOffset != 0 || \
85 objectInfoPtr->payloadSize != 0 )
86 return( FALSE );
87 }
88 if( objectInfoPtr->keySize < 0 || \
89 objectInfoPtr->keySize > CRYPT_MAX_KEYSIZE || \
90 objectInfoPtr->saltSize < 0 || \
91 objectInfoPtr->saltSize > CRYPT_MAX_HASHSIZE || \
92 objectInfoPtr->iterations < 0 || \
93 objectInfoPtr->iterations > MAX_KEYSETUP_ITERATIONS )
94 return( FALSE );
95 objectInfoPtr = &pkcs12infoPtr->certInfo;
96 if( objectInfoPtr->data != NULL )
97 {
98 /* Make sure that the payload is contained within the data. The
99 payload may be the same as the data, so we can have a start offset
100 of 0 and a size equal to the payload size */
101 if( objectInfoPtr->dataSize <= 0 || \
102 objectInfoPtr->dataSize > MAX_INTLENGTH_SHORT || \
103 objectInfoPtr->payloadOffset < 0 || \
104 objectInfoPtr->payloadOffset >= objectInfoPtr->dataSize || \
105 objectInfoPtr->payloadSize < 0 || \
106 objectInfoPtr->payloadSize > objectInfoPtr->dataSize )
107 return( FALSE );
108 }
109 else
110 {
111 if( objectInfoPtr->dataSize != 0 || \
112 objectInfoPtr->payloadOffset != 0 || \
113 objectInfoPtr->payloadSize != 0 )
114 return( FALSE );
115 }
116 if( objectInfoPtr->keySize < 0 || \
117 objectInfoPtr->keySize > CRYPT_MAX_KEYSIZE || \
118 objectInfoPtr->saltSize < 0 || \
119 objectInfoPtr->saltSize > CRYPT_MAX_HASHSIZE || \
120 objectInfoPtr->iterations < 0 || \
121 objectInfoPtr->iterations > MAX_KEYSETUP_ITERATIONS )
122 return( FALSE );
123
124 /* Check that the crypto-related fields are in order. This is a general
125 check for reasonable values that's more targeted at catching
126 inadvertent memory corruption than a strict sanity check */
127 if( pkcs12infoPtr->macSaltSize < 0 || \
128 pkcs12infoPtr->macSaltSize > MAX_INTLENGTH_SHORT || \
129 pkcs12infoPtr->macIterations < 0 || \
130 pkcs12infoPtr->macIterations > MAX_INTLENGTH )
131 return( FALSE );
132
133 return( TRUE );
134 }
135
136 /* Locate a PKCS #12 object based on an ID */
137
138 #define matchID( src, srcLen, dest, destLen ) \
139 ( ( srcLen ) > 0 && ( srcLen ) == ( destLen ) && \
140 !memcmp( ( src ), ( dest ), ( destLen ) ) )
141
142 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1 ) ) \
pkcs12FindEntry(IN_ARRAY (noPkcs12objects)const PKCS12_INFO * pkcs12info,IN_LENGTH_SHORT const int noPkcs12objects,IN_KEYID const CRYPT_KEYID_TYPE keyIDtype,IN_BUFFER_OPT (keyIDlength)const void * keyID,IN_LENGTH_KEYID_Z const int keyIDlength,const BOOLEAN isWildcardMatch)143 PKCS12_INFO *pkcs12FindEntry( IN_ARRAY( noPkcs12objects ) \
144 const PKCS12_INFO *pkcs12info,
145 IN_LENGTH_SHORT const int noPkcs12objects,
146 IN_KEYID const CRYPT_KEYID_TYPE keyIDtype,
147 IN_BUFFER_OPT( keyIDlength ) const void *keyID,
148 IN_LENGTH_KEYID_Z const int keyIDlength,
149 const BOOLEAN isWildcardMatch )
150 {
151 int i;
152
153 assert( isReadPtr( pkcs12info, \
154 sizeof( PKCS12_INFO ) * noPkcs12objects ) );
155 assert( ( keyID == NULL && keyIDlength == 0 ) || \
156 isReadPtr( keyID, keyIDlength ) );
157
158 REQUIRES_N( noPkcs12objects >= 1 && \
159 noPkcs12objects < MAX_INTLENGTH_SHORT );
160 REQUIRES_N( keyIDtype == CRYPT_KEYID_NAME || \
161 keyIDtype == CRYPT_KEYID_URI || \
162 keyIDtype == CRYPT_IKEYID_KEYID );
163 REQUIRES_N( ( keyID == NULL && keyIDlength == 0 ) || \
164 ( keyID != NULL && \
165 keyIDlength > 0 && keyIDlength < MAX_ATTRIBUTE_SIZE ) );
166 REQUIRES_N( ( isWildcardMatch && keyID == NULL ) || !isWildcardMatch );
167
168 /* Try and locate the appropriate object in the PKCS #12 collection */
169 for( i = 0; i < noPkcs12objects && i < FAILSAFE_ITERATIONS_MED; i++ )
170 {
171 const PKCS12_INFO *pkcs12infoPtr = &pkcs12info[ i ];
172
173 /* If there's no entry at this position, continue */
174 if( pkcs12infoPtr->flags == PKCS12_FLAG_NONE )
175 continue;
176
177 ENSURES_N( sanityCheck( pkcs12infoPtr ) );
178
179 /* If we're doing a wildcard matches, match the first private-key
180 entry. This is required because PKCS #12 provides almost no
181 useful indexing information, and works because most keysets
182 contain only a single entry */
183 if( isWildcardMatch )
184 {
185 if( pkcs12infoPtr->keyInfo.data == NULL )
186 continue; /* No private-key data present, continue */
187 return( ( PKCS12_INFO * ) pkcs12infoPtr );
188 }
189
190 /* Check for a match based on the ID type */
191 switch( keyIDtype )
192 {
193 case CRYPT_KEYID_NAME:
194 case CRYPT_KEYID_URI:
195 if( matchID( pkcs12infoPtr->label, pkcs12infoPtr->labelLength,
196 keyID, keyIDlength ) )
197 return( ( PKCS12_INFO * ) pkcs12infoPtr );
198 break;
199
200 case CRYPT_IKEYID_KEYID:
201 if( matchID( pkcs12infoPtr->id, pkcs12infoPtr->idLength,
202 keyID, keyIDlength ) )
203 return( ( PKCS12_INFO * ) pkcs12infoPtr );
204 break;
205
206 default:
207 retIntError_Null();
208 }
209 }
210 ENSURES_N( i < FAILSAFE_ITERATIONS_MED );
211
212 return( NULL );
213 }
214
215 /* Find a free PKCS #12 entry */
216
217 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1 ) ) \
pkcs12FindFreeEntry(IN_ARRAY (noPkcs12objects)const PKCS12_INFO * pkcs12info,IN_LENGTH_SHORT const int noPkcs12objects,OUT_OPT_INDEX (noPkcs12objects)int * index)218 PKCS12_INFO *pkcs12FindFreeEntry( IN_ARRAY( noPkcs12objects ) \
219 const PKCS12_INFO *pkcs12info,
220 IN_LENGTH_SHORT const int noPkcs12objects,
221 OUT_OPT_INDEX( noPkcs12objects ) int *index )
222 {
223 int i;
224
225 assert( isReadPtr( pkcs12info, \
226 sizeof( PKCS12_INFO ) * noPkcs12objects ) );
227 assert( ( index == NULL ) || isWritePtr( index, sizeof( int ) ) );
228
229 REQUIRES_N( noPkcs12objects >= 1 && \
230 noPkcs12objects < MAX_INTLENGTH_SHORT );
231
232 /* Clear return value */
233 if( index != NULL )
234 *index = CRYPT_ERROR;
235
236 for( i = 0; i < noPkcs12objects && i < FAILSAFE_ITERATIONS_MED; i++ )
237 {
238 if( pkcs12info[ i ].flags == PKCS12_FLAG_NONE )
239 break;
240 }
241 ENSURES_N( i < FAILSAFE_ITERATIONS_MED );
242 if( i >= noPkcs12objects )
243 return( NULL );
244
245 /* Remember the index value (used for enumerating PKCS #12 entries) for
246 this entry if required */
247 if( index != NULL )
248 *index = i;
249
250 return( ( PKCS12_INFO * ) &pkcs12info[ i ] );
251 }
252
253 /* Free object entries */
254
255 STDC_NONNULL_ARG( ( 1 ) ) \
pkcs12freeObjectEntry(INOUT PKCS12_OBJECT_INFO * pkcs12objectInfo)256 void pkcs12freeObjectEntry( INOUT PKCS12_OBJECT_INFO *pkcs12objectInfo )
257 {
258 void *dataPtr = ( void * ) pkcs12objectInfo->data;
259 /* Although the data is declared 'const' since it can't be
260 modified, we still have to be able to zeroise it on free so
261 we override the const for this */
262
263 assert( isWritePtr( pkcs12objectInfo, sizeof( PKCS12_OBJECT_INFO ) ) );
264
265 zeroise( dataPtr, pkcs12objectInfo->dataSize );
266 clFree( "pkcs12freeObjectEntry", dataPtr );
267 zeroise( pkcs12objectInfo, sizeof( PKCS12_OBJECT_INFO ) );
268 }
269
270 STDC_NONNULL_ARG( ( 1 ) ) \
pkcs12freeEntry(INOUT PKCS12_INFO * pkcs12info)271 void pkcs12freeEntry( INOUT PKCS12_INFO *pkcs12info )
272 {
273 assert( isWritePtr( pkcs12info, sizeof( PKCS12_INFO ) ) );
274
275 if( pkcs12info->macInitialised )
276 krnlSendNotifier( pkcs12info->iMacContext, IMESSAGE_DECREFCOUNT );
277 if( pkcs12info->keyInfo.data != NULL )
278 pkcs12freeObjectEntry( &pkcs12info->keyInfo );
279 if( pkcs12info->certInfo.data != NULL )
280 pkcs12freeObjectEntry( &pkcs12info->certInfo );
281
282 zeroise( pkcs12info, sizeof( PKCS12_INFO ) );
283 }
284
285 STDC_NONNULL_ARG( ( 1 ) ) \
INOUT_ARRAY(noPkcs12objects)286 void pkcs12Free( INOUT_ARRAY( noPkcs12objects ) PKCS12_INFO *pkcs12info,
287 IN_RANGE( 1, MAX_PKCS12_OBJECTS ) const int noPkcs12objects )
288 {
289 int i;
290
291 assert( isWritePtr( pkcs12info, \
292 sizeof( PKCS12_INFO ) * noPkcs12objects ) );
293
294 REQUIRES_V( noPkcs12objects >= 1 && \
295 noPkcs12objects <= MAX_PKCS12_OBJECTS );
296
297 for( i = 0; i < noPkcs12objects && i < FAILSAFE_ITERATIONS_MED; i++ )
298 pkcs12freeEntry( &pkcs12info[ i ] );
299 ENSURES_V( i < FAILSAFE_ITERATIONS_MED );
300 zeroise( pkcs12info, sizeof( PKCS12_INFO ) * noPkcs12objects );
301 }
302
303 /* Read the header of a PKCS #12 keyset */
304
305 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
readPkcs12header(INOUT STREAM * stream,OUT_INT_Z long * endPosPtr,INOUT ERROR_INFO * errorInfo)306 static int readPkcs12header( INOUT STREAM *stream,
307 OUT_INT_Z long *endPosPtr,
308 INOUT ERROR_INFO *errorInfo )
309 {
310 long version, endPos DUMMY_INIT, currentPos;
311 int status;
312
313 assert( isWritePtr( stream, sizeof( STREAM ) ) );
314 assert( isWritePtr( endPosPtr, sizeof( long ) ) );
315 assert( isWritePtr( errorInfo, sizeof( ERROR_INFO ) ) );
316
317 /* Clear return value */
318 *endPosPtr = 0;
319
320 /* Read the outer header and make sure that it's valid */
321 readSequence( stream, NULL );
322 status = readShortInteger( stream, &version );
323 if( cryptStatusOK( status ) && version != 3 )
324 status = CRYPT_ERROR_BADDATA;
325 if( cryptStatusOK( status ) )
326 {
327 status = readCMSheader( stream, dataOIDinfo,
328 FAILSAFE_ARRAYSIZE( dataOIDinfo, OID_INFO ),
329 &endPos, READCMS_FLAG_DEFINITELENGTH_OPT );
330 }
331 if( cryptStatusError( status ) )
332 {
333 retExt( status,
334 ( status, errorInfo,
335 "Invalid PKCS #12 keyset header" ) );
336 }
337
338 /* If we couldn't get the length from the CMS header, try again with the
339 next level of nested data */
340 if( endPos == CRYPT_UNUSED )
341 {
342 int length;
343
344 status = readSequence( stream, &length );
345 if( cryptStatusOK( status ) && length == CRYPT_UNUSED )
346 {
347 retExt( CRYPT_ERROR_BADDATA,
348 ( CRYPT_ERROR_BADDATA, errorInfo,
349 "Can't process indefinite-length PKCS #12 "
350 "content" ) );
351 }
352 endPos = length; /* int -> long, readSequence() requires an int */
353 }
354 else
355 {
356 const int startPos = stell( stream );
357
358 /* Just skip the next level of nesting. We don't rely on the value
359 returned from readSequence() in case it has an indefinite length,
360 since we've already got a definite length earlier */
361 status = readSequence( stream, NULL );
362 if( cryptStatusOK( status ) )
363 endPos -= ( stell( stream ) - startPos );
364 }
365 if( cryptStatusError( status ) )
366 {
367 retExt( status,
368 ( status, errorInfo,
369 "Invalid PKCS #12 keyset inner header" ) );
370 }
371
372 /* Make sure that the length information is sensible */
373 currentPos = stell( stream );
374 if( endPos < 16 + MIN_OBJECT_SIZE || \
375 currentPos + endPos >= MAX_INTLENGTH_SHORT )
376 {
377 retExt( CRYPT_ERROR_BADDATA,
378 ( CRYPT_ERROR_BADDATA, errorInfo,
379 "Invalid PKCS #12 keyset length information" ) );
380 }
381 *endPosPtr = currentPos + endPos;
382
383 return( CRYPT_OK );
384 }
385
386 /****************************************************************************
387 * *
388 * Crypto Functions *
389 * *
390 ****************************************************************************/
391
392 /* Set up the parameters used to derive a password for encryption/MACing */
393
394 CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 4, 5 ) ) \
initDeriveParams(IN_HANDLE const CRYPT_USER cryptOwner,OUT_BUFFER (saltMaxLength,* saltLength)void * salt,IN_LENGTH_SHORT_MIN (KEYWRAP_SALTSIZE)const int saltMaxLength,OUT_LENGTH_BOUNDED_Z (saltMaxLength)int * saltLength,OUT_INT_Z int * iterations)395 static int initDeriveParams( IN_HANDLE const CRYPT_USER cryptOwner,
396 OUT_BUFFER( saltMaxLength, *saltLength ) \
397 void *salt,
398 IN_LENGTH_SHORT_MIN( KEYWRAP_SALTSIZE ) \
399 const int saltMaxLength,
400 OUT_LENGTH_BOUNDED_Z( saltMaxLength ) \
401 int *saltLength,
402 OUT_INT_Z int *iterations )
403 {
404 MESSAGE_DATA msgData;
405 int value, status;
406
407 assert( isWritePtr( salt, saltMaxLength ) );
408 assert( isWritePtr( saltLength, sizeof( int ) ) );
409 assert( isWritePtr( iterations, sizeof( int ) ) );
410
411 REQUIRES( cryptOwner == DEFAULTUSER_OBJECT_HANDLE || \
412 isHandleRangeValid( cryptOwner ) );
413 REQUIRES( saltMaxLength >= KEYWRAP_SALTSIZE && \
414 saltMaxLength < MAX_INTLENGTH_SHORT );
415
416 /* Clear return values */
417 memset( salt, 0, min( 16, saltMaxLength ) );
418 *saltLength = 0;
419 *iterations = 0;
420
421 /* Generate the salt */
422 setMessageData( &msgData, salt, KEYWRAP_SALTSIZE );
423 status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
424 &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
425 if( cryptStatusError( status ) )
426 return( status );
427 *saltLength = KEYWRAP_SALTSIZE;
428
429 /* In the interests of luser-proofing we force the use of a safe minimum
430 number of iterations */
431 status = krnlSendMessage( cryptOwner, IMESSAGE_GETATTRIBUTE,
432 &value, CRYPT_OPTION_KEYING_ITERATIONS );
433 if( cryptStatusError( status ) || value < MIN_KEYING_ITERATIONS )
434 value = MIN_KEYING_ITERATIONS;
435 *iterations = value;
436
437 return( CRYPT_OK );
438 }
439
440 /* Set up an encryption/MAC context */
441
442 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4, 6 ) ) \
initContext(OUT_HANDLE_OPT CRYPT_CONTEXT * iCryptContext,IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo,IN_LENGTH_KEY const int keySize,IN_BUFFER (passwordLength)const void * password,IN_LENGTH_TEXT const int passwordLength,IN_BUFFER (saltLength)const void * salt,IN_LENGTH_SHORT const int saltLength,IN_INT const int iterations,const BOOLEAN isCryptContext)443 static int initContext( OUT_HANDLE_OPT CRYPT_CONTEXT *iCryptContext,
444 IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo,
445 IN_LENGTH_KEY const int keySize,
446 IN_BUFFER( passwordLength ) const void *password,
447 IN_LENGTH_TEXT const int passwordLength,
448 IN_BUFFER( saltLength ) const void *salt,
449 IN_LENGTH_SHORT const int saltLength,
450 IN_INT const int iterations,
451 const BOOLEAN isCryptContext )
452 {
453 CRYPT_CONTEXT iLocalCryptContext;
454 MESSAGE_CREATEOBJECT_INFO createInfo;
455 MECHANISM_DERIVE_INFO deriveInfo;
456 MESSAGE_DATA msgData;
457 BYTE key[ CRYPT_MAX_KEYSIZE + 8 ], iv[ CRYPT_MAX_IVSIZE + 8 ];
458 BYTE saltData[ 1 + CRYPT_MAX_IVSIZE + 8 ];
459 int ivSize DUMMY_INIT, localKeySize = keySize, status;
460
461 assert( isWritePtr( iCryptContext, sizeof( CRYPT_CONTEXT ) ) );
462 assert( isReadPtr( password, passwordLength ) );
463 assert( isReadPtr( salt, saltLength ) );
464
465 REQUIRES( ( isCryptContext && isConvAlgo( cryptAlgo ) ) || \
466 ( !isCryptContext && isMacAlgo( cryptAlgo ) ) );
467 REQUIRES( keySize >= bitsToBytes( 40 ) && keySize <= CRYPT_MAX_KEYSIZE );
468 /* 40 bits is a special case for certificates encrypted with
469 RC2-40 */
470 REQUIRES( passwordLength >= MIN_NAME_LENGTH && \
471 passwordLength <= CRYPT_MAX_TEXTSIZE );
472 REQUIRES( saltLength >= 1 && saltLength <= CRYPT_MAX_HASHSIZE );
473 REQUIRES( iterations >= 1 && iterations < MAX_INTLENGTH );
474
475 /* Clear return value */
476 *iCryptContext = CRYPT_ERROR;
477
478 /* Create the encryption/MAC context and get any required parameter
479 information. Note that this assumes that the encryption algorithm
480 is a block cipher, which always seems to be the case */
481 setMessageCreateObjectInfo( &createInfo, cryptAlgo );
482 status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
483 &createInfo, OBJECT_TYPE_CONTEXT );
484 if( cryptStatusError( status ) )
485 return( status );
486 iLocalCryptContext = createInfo.cryptHandle;
487 if( isCryptContext )
488 status = krnlSendMessage( iLocalCryptContext, IMESSAGE_GETATTRIBUTE,
489 &ivSize, CRYPT_CTXINFO_IVSIZE );
490 if( cryptStatusError( status ) )
491 {
492 krnlSendNotifier( iLocalCryptContext, IMESSAGE_DECREFCOUNT );
493 return( status );
494 }
495
496 /* Since the salt also includes a diversifier as its first byte we copy
497 it to a working buffer with room for the extra data byte */
498 memcpy( saltData + 1, salt, saltLength );
499
500 /* Derive the encryption/MAC key and optional IV from the password */
501 if( isCryptContext )
502 saltData[ 0 ] = KEYWRAP_ID_WRAPKEY;
503 else
504 saltData[ 0 ] = KEYWRAP_ID_MACKEY;
505 setMechanismDeriveInfo( &deriveInfo, key, keySize, password,
506 passwordLength, CRYPT_ALGO_SHA1, saltData,
507 saltLength + 1, iterations );
508 status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_DERIVE,
509 &deriveInfo, MECHANISM_DERIVE_PKCS12 );
510 if( cryptStatusOK( status ) && isCryptContext )
511 {
512 saltData[ 0 ] = KEYWRAP_ID_IV;
513 setMechanismDeriveInfo( &deriveInfo, iv, ivSize, password,
514 passwordLength, CRYPT_ALGO_SHA1, saltData,
515 saltLength + 1, iterations );
516 status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_DERIVE,
517 &deriveInfo, MECHANISM_DERIVE_PKCS12 );
518 }
519 clearMechanismInfo( &deriveInfo );
520 if( cryptStatusError( status ) )
521 {
522 zeroise( key, CRYPT_MAX_KEYSIZE );
523 zeroise( iv, CRYPT_MAX_IVSIZE );
524 krnlSendNotifier( iLocalCryptContext, IMESSAGE_DECREFCOUNT );
525 return( status );
526 }
527
528 /* We need to add special-case processing for RC2-40, which is still
529 universally used by Windows and possibly other implementations as
530 well. The kernel (and pretty much everything else) won't allow keys
531 of less then MIN_KEYSIZE bytes, to get around this we create a
532 pseudo-key consisting of two copies of the string "PKCS#12" followed
533 by the actual key, with a total length of 19 bytes / 152 bits. The
534 RC2 code checks for this special string at the start of any key that
535 it loads and only uses the last 40 bits. This is a horrible kludge,
536 but RC2 is disabled by default (unless USE_PKCS12 is defined) so the
537 only time that it'll ever be used anyway is as RC2-40 */
538 if( cryptAlgo == CRYPT_ALGO_RC2 && keySize == bitsToBytes( 40 ) )
539 {
540 memmove( key + 14, key, bitsToBytes( 40 ) );
541 memcpy( key, "PKCS#12PKCS#12", 14 );
542 localKeySize = 14 + bitsToBytes( 40 );
543 }
544
545 /* Create an encryption/MAC context and load the key and IV into it */
546 setMessageData( &msgData, key, localKeySize );
547 status = krnlSendMessage( iLocalCryptContext, IMESSAGE_SETATTRIBUTE_S,
548 &msgData, CRYPT_CTXINFO_KEY );
549 if( cryptStatusOK( status ) && isCryptContext )
550 {
551 setMessageData( &msgData, iv, ivSize );
552 status = krnlSendMessage( iLocalCryptContext,
553 IMESSAGE_SETATTRIBUTE_S, &msgData,
554 CRYPT_CTXINFO_IV );
555 }
556 zeroise( key, CRYPT_MAX_KEYSIZE );
557 zeroise( iv, CRYPT_MAX_IVSIZE );
558 if( cryptStatusError( status ) )
559 {
560 krnlSendNotifier( iLocalCryptContext, IMESSAGE_DECREFCOUNT );
561 return( status );
562 }
563 *iCryptContext = iLocalCryptContext;
564
565 return( CRYPT_OK );
566 }
567
568 /* Create key wrap and MAC contexts from a password */
569
570 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
createPkcs12KeyWrapContext(INOUT PKCS12_OBJECT_INFO * pkcs12objectInfo,IN_HANDLE const CRYPT_USER cryptOwner,IN_BUFFER (passwordLength)const char * password,IN_LENGTH_TEXT const int passwordLength,OUT_HANDLE_OPT CRYPT_CONTEXT * iCryptContext,const BOOLEAN initParams)571 int createPkcs12KeyWrapContext( INOUT PKCS12_OBJECT_INFO *pkcs12objectInfo,
572 IN_HANDLE const CRYPT_USER cryptOwner,
573 IN_BUFFER( passwordLength ) const char *password,
574 IN_LENGTH_TEXT const int passwordLength,
575 OUT_HANDLE_OPT CRYPT_CONTEXT *iCryptContext,
576 const BOOLEAN initParams )
577 {
578 int status;
579
580 assert( isWritePtr( pkcs12objectInfo, sizeof( PKCS12_OBJECT_INFO ) ) );
581 assert( isReadPtr( password, passwordLength ) );
582 assert( isWritePtr( iCryptContext, sizeof( CRYPT_CONTEXT ) ) );
583
584 REQUIRES( cryptOwner == DEFAULTUSER_OBJECT_HANDLE || \
585 isHandleRangeValid( cryptOwner ) );
586 REQUIRES( passwordLength >= MIN_NAME_LENGTH && \
587 passwordLength <= CRYPT_MAX_TEXTSIZE );
588
589 /* Clear return value */
590 *iCryptContext = CRYPT_ERROR;
591
592 /* Set up the parameters for the encryption key and IV if required.
593 The only (useful) encryption algorithm that's available is 3DES, so
594 we hardcode that in */
595 if( initParams )
596 {
597 pkcs12objectInfo->cryptAlgo = CRYPT_ALGO_3DES;
598 pkcs12objectInfo->keySize = bitsToBytes( 192 );
599 status = initDeriveParams( cryptOwner, pkcs12objectInfo->salt,
600 CRYPT_MAX_HASHSIZE,
601 &pkcs12objectInfo->saltSize,
602 &pkcs12objectInfo->iterations );
603 if( cryptStatusError( status ) )
604 return( status );
605 }
606
607 /* Derive the encryption key and IV from the password */
608 return( initContext( iCryptContext, pkcs12objectInfo->cryptAlgo,
609 pkcs12objectInfo->keySize, password,
610 passwordLength, pkcs12objectInfo->salt,
611 pkcs12objectInfo->saltSize,
612 pkcs12objectInfo->iterations, TRUE ) );
613 }
614
615 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
createPkcs12MacContext(INOUT PKCS12_INFO * pkcs12info,IN_HANDLE const CRYPT_USER cryptOwner,IN_BUFFER (passwordLength)const char * password,IN_LENGTH_TEXT const int passwordLength,OUT_HANDLE_OPT CRYPT_CONTEXT * iCryptContext,const BOOLEAN initParams)616 int createPkcs12MacContext( INOUT PKCS12_INFO *pkcs12info,
617 IN_HANDLE const CRYPT_USER cryptOwner,
618 IN_BUFFER( passwordLength ) const char *password,
619 IN_LENGTH_TEXT const int passwordLength,
620 OUT_HANDLE_OPT CRYPT_CONTEXT *iCryptContext,
621 const BOOLEAN initParams )
622 {
623 int status;
624
625 assert( isWritePtr( pkcs12info, sizeof( PKCS12_INFO ) ) );
626 assert( isReadPtr( password, passwordLength ) );
627 assert( isWritePtr( iCryptContext, sizeof( CRYPT_CONTEXT ) ) );
628
629 REQUIRES( cryptOwner == DEFAULTUSER_OBJECT_HANDLE || \
630 isHandleRangeValid( cryptOwner ) );
631 REQUIRES( passwordLength >= MIN_NAME_LENGTH && \
632 passwordLength <= CRYPT_MAX_TEXTSIZE );
633
634 /* Clear return value */
635 *iCryptContext = CRYPT_ERROR;
636
637 /* Set up the parameters used to derive the MAC key if required */
638 if( initParams )
639 {
640 status = initDeriveParams( cryptOwner, pkcs12info->macSalt,
641 CRYPT_MAX_HASHSIZE,
642 &pkcs12info->macSaltSize,
643 &pkcs12info->macIterations );
644 if( cryptStatusError( status ) )
645 return( status );
646 }
647
648 /* Derive the MAC key from the password. PKCS #12 currently hardcodes
649 this to HMAC-SHA1 with a 160-bit key */
650 return( initContext( iCryptContext, CRYPT_ALGO_HMAC_SHA1,
651 20, password, passwordLength, pkcs12info->macSalt,
652 pkcs12info->macSaltSize,
653 pkcs12info->macIterations, FALSE ) );
654 }
655
656 /****************************************************************************
657 * *
658 * Init/Shutdown Functions *
659 * *
660 ****************************************************************************/
661
662 /* A PKCS #12 keyset can contain steaming mounds of keys and whatnot, so
663 when we open it we parse the contents into memory for later use */
664
665 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)666 static int initFunction( INOUT KEYSET_INFO *keysetInfoPtr,
667 STDC_UNUSED const char *name,
668 STDC_UNUSED const int nameLength,
669 IN_ENUM( CRYPT_KEYOPT ) const CRYPT_KEYOPT_TYPE options )
670 {
671 PKCS12_INFO *pkcs12info;
672 STREAM *stream = &keysetInfoPtr->keysetFile->stream;
673 long endPos DUMMY_INIT;
674 int status;
675
676 assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
677
678 REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
679 keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS12 );
680 REQUIRES( name == NULL && nameLength == 0 );
681 REQUIRES( options >= CRYPT_KEYOPT_NONE && options < CRYPT_KEYOPT_LAST );
682
683 /* If we're opening an existing keyset skip the outer header. We do
684 this before we perform any setup operations to weed out potential
685 problem keysets */
686 if( options != CRYPT_KEYOPT_CREATE )
687 {
688 status = readPkcs12header( stream, &endPos, KEYSET_ERRINFO );
689 if( cryptStatusError( status ) )
690 return( status );
691 }
692
693 /* Allocate the PKCS #12 object information */
694 if( ( pkcs12info = clAlloc( "initFunction", \
695 sizeof( PKCS12_INFO ) * \
696 MAX_PKCS12_OBJECTS ) ) == NULL )
697 return( CRYPT_ERROR_MEMORY );
698 memset( pkcs12info, 0, sizeof( PKCS12_INFO ) * MAX_PKCS12_OBJECTS );
699 keysetInfoPtr->keyData = pkcs12info;
700 keysetInfoPtr->keyDataSize = sizeof( PKCS12_INFO ) * MAX_PKCS12_OBJECTS;
701 keysetInfoPtr->keyDataNoObjects = MAX_PKCS12_OBJECTS;
702
703 /* If this is a newly-created keyset, there's nothing left to do */
704 if( options == CRYPT_KEYOPT_CREATE )
705 return( CRYPT_OK );
706
707 /* Read all of the keys in the keyset */
708 status = pkcs12ReadKeyset( &keysetInfoPtr->keysetFile->stream,
709 pkcs12info, MAX_PKCS12_OBJECTS, endPos,
710 KEYSET_ERRINFO );
711 if( cryptStatusError( status ) )
712 {
713 clFree( "initFunction", keysetInfoPtr->keyData );
714 keysetInfoPtr->keyData = NULL;
715 keysetInfoPtr->keyDataSize = 0;
716 if( options != CRYPT_KEYOPT_CREATE )
717 {
718 /* Reset the stream position to account for the header
719 information that we've already read */
720 sseek( stream, 0 ) ;
721 }
722 return( status );
723 }
724
725 return( CRYPT_OK );
726 }
727
728 /* Shut down the PKCS #12 state, flushing information to disk if necessary */
729
730 STDC_NONNULL_ARG( ( 1 ) ) \
shutdownFunction(INOUT KEYSET_INFO * keysetInfoPtr)731 static int shutdownFunction( INOUT KEYSET_INFO *keysetInfoPtr )
732 {
733 int status = CRYPT_OK;
734
735 assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
736
737 REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
738 keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS12 );
739
740 /* If the contents have been changed, allocate a working I/O buffer for
741 the duration of the flush and commit the changes to disk */
742 if( keysetInfoPtr->flags & KEYSET_DIRTY )
743 {
744 STREAM *stream = &keysetInfoPtr->keysetFile->stream;
745 BYTE buffer[ STREAM_BUFSIZE + 8 ];
746
747 sseek( stream, 0 );
748 memset( buffer, 0, STREAM_BUFSIZE );
749 /* Keep static analysers happy */
750 sioctlSetString( stream, STREAM_IOCTL_IOBUFFER, buffer,
751 STREAM_BUFSIZE );
752 status = pkcs12Flush( stream, keysetInfoPtr->keyData,
753 keysetInfoPtr->keyDataNoObjects );
754 sioctlSet( stream, STREAM_IOCTL_IOBUFFER, 0 );
755 if( status == OK_SPECIAL )
756 {
757 keysetInfoPtr->flags |= KEYSET_EMPTY;
758 status = CRYPT_OK;
759 }
760 }
761
762 /* Free the PKCS #12 object information */
763 if( keysetInfoPtr->keyData != NULL )
764 {
765 pkcs12Free( keysetInfoPtr->keyData, MAX_PKCS12_OBJECTS );
766 zeroise( keysetInfoPtr->keyData, keysetInfoPtr->keyDataSize );
767 clFree( "shutdownFunction", keysetInfoPtr->keyData );
768 }
769
770 if( cryptStatusError( status ) )
771 {
772 retExt( status,
773 ( status, KEYSET_ERRINFO,
774 "Couldn't send PKCS #12 data to persistent storage" ) );
775 }
776
777 return( CRYPT_OK );
778 }
779
780 /****************************************************************************
781 * *
782 * Keyset Access Routines *
783 * *
784 ****************************************************************************/
785
786 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
setAccessMethodPKCS12(INOUT KEYSET_INFO * keysetInfoPtr)787 int setAccessMethodPKCS12( INOUT KEYSET_INFO *keysetInfoPtr )
788 {
789 int status;
790
791 assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
792
793 REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
794 keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS12 );
795
796 /* Set the access method pointers */
797 FNPTR_SET( keysetInfoPtr->initFunction, initFunction );
798 FNPTR_SET( keysetInfoPtr->shutdownFunction, shutdownFunction );
799 status = initPKCS12get( keysetInfoPtr );
800 if( cryptStatusOK( status ) )
801 status = initPKCS12set( keysetInfoPtr );
802 return( status );
803 }
804 #endif /* USE_PKCS12 */
805