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