cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
pkcs12_wr.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib PKCS #12 Write Routines *
4 * Copyright Peter Gutmann 1997-2002 *
5 * *
6 ****************************************************************************/
7 
8 /* This code is based on breakms.c, which breaks the encryption of several of
9  MS's extremely broken PKCS #12 implementations. Because of the security
10  problems associated with key files produced by MS software and the fact
11  that this format is commonly used to spray private keys around without any
12  regard to their sensitivity, cryptlib doesn't support it as a writeable
13  format. As one vendor who shall remain anonymous put it, "We don't want
14  to put our keys anywhere where MS software can get to them" */
15 
16 #if defined( INC_ALL )
17  #include "crypt.h"
18  #include "asn1.h"
19  #include "asn1_ext.h"
20  #include "keyset.h"
21  #include "pkcs12.h"
22 #else
23  #include "crypt.h"
24  #include "enc_dec/asn1.h"
25  #include "enc_dec/asn1_ext.h"
26  #include "keyset/keyset.h"
27  #include "keyset/pkcs12.h"
28 #endif /* Compiler-specific includes */
29 
30 #ifdef USE_PKCS12
31 
32 /****************************************************************************
33 * *
34 * Utility Functions *
35 * *
36 ****************************************************************************/
37 
38 /* Write the garbled PKCS #12 version of a CMS wrapper */
39 
40 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
41 static int writeNonCMSheader( INOUT STREAM *stream,
42  IN_BUFFER( oidLength ) const BYTE *oid,
43  IN_RANGE( 1, MAX_OID_SIZE ) const int oidLength,
44  IN_LENGTH_SHORT const int length,
45  IN_LENGTH_SHORT const int attrDataLength )
46  {
47  assert( isWritePtr( stream, sizeof( STREAM ) ) );
48  assert( isReadPtr( oid, oidLength ) );
49 
50  REQUIRES( oidLength >= MIN_OID_SIZE && oidLength <= MAX_OID_SIZE );
51  REQUIRES( length > 0 && length < MAX_INTLENGTH_SHORT );
52  REQUIRES( attrDataLength > 0 && attrDataLength < MAX_INTLENGTH_SHORT );
53 
54  writeSequence( stream, ( int ) \
55  ( sizeofOID( oid ) + \
56  sizeofObject( sizeofObject( length ) ) + \
57  sizeofObject( attrDataLength ) ) );
58  swrite( stream, oid, oidLength );
59  writeConstructed( stream, ( int ) sizeofObject( length ), 0 );
60  return( writeSequence( stream, length ) );
61  }
62 
63 /* Write the MAC data at the end of the keyset */
64 
66 static int sizeofMacData( const PKCS12_INFO *pkcs12info )
67  {
68  assert( isReadPtr( pkcs12info, sizeof( PKCS12_INFO ) ) );
69 
70  return( sizeofObject( \
72  sizeofObject( 20 ) ) + \
73  sizeofObject( pkcs12info->macSaltSize ) + \
74  sizeofShortInteger( pkcs12info->macIterations ) );
75  }
76 
77 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
78 static int writeMacData( INOUT STREAM *stream,
79  const PKCS12_INFO *pkcs12info )
80  {
82  BYTE macBuffer[ CRYPT_MAX_HASHSIZE + 8 ];
83  const int macDataSize = sizeofMacData( pkcs12info );
84  int status;
85 
86  assert( isWritePtr( stream, sizeof( STREAM ) ) );
87  assert( isReadPtr( pkcs12info, sizeof( PKCS12_INFO ) ) );
88 
89  REQUIRES( macDataSize >= 32 && macDataSize < MAX_INTLENGTH_SHORT );
90 
91  /* Wrap up the MACing and get the MAC value */
92  status = krnlSendMessage( pkcs12info->iMacContext,
93  IMESSAGE_CTX_HASH, "", 0 );
94  if( cryptStatusError( status ) )
95  return( status );
96  setMessageData( &msgData, macBuffer, CRYPT_MAX_HASHSIZE );
97  status = krnlSendMessage( pkcs12info->iMacContext,
98  IMESSAGE_GETATTRIBUTE_S, &msgData,
100  if( cryptStatusError( status ) )
101  return( status );
102 
103  /* Write the MAC data. Despite the fact that the algorithm being used
104  is HMAC, the OID that we have to write is the one for plain SHA-1 */
105  writeSequence( stream, macDataSize );
106  writeSequence( stream, sizeofAlgoID( CRYPT_ALGO_SHA ) + \
107  sizeofObject( 20 ) );
108  writeAlgoID( stream, CRYPT_ALGO_SHA );
109  writeOctetString( stream, macBuffer, msgData.length, DEFAULT_TAG );
110  writeOctetString( stream, pkcs12info->macSalt, pkcs12info->macSaltSize,
111  DEFAULT_TAG );
112  return( writeShortInteger( stream, pkcs12info->macIterations,
113  DEFAULT_TAG ) );
114  }
115 
116 /****************************************************************************
117 * *
118 * Write a Key/Certiifcate *
119 * *
120 ****************************************************************************/
121 
122 /* Write an encrypted private key */
123 
125 static int writePrivateKey( INOUT PKCS12_OBJECT_INFO *keyObjectInfo,
127  IN_HANDLE const CRYPT_HANDLE iKeyWrapContext )
128  {
130  STREAM stream;
131  void *privKeyData;
132  int privKeyDataSize = DUMMY_INIT, pbeInfoDataSize, headerSize, status;
133 
134  assert( isWritePtr( keyObjectInfo, sizeof( PKCS12_OBJECT_INFO ) ) );
135 
136  REQUIRES( isHandleRangeValid( iPrivKeyContext ) );
137  REQUIRES( isHandleRangeValid( iKeyWrapContext ) );
138 
139  /* Calculate the eventual encrypted key size and allocate storage for it */
140  setMechanismWrapInfo( &mechanismInfo, NULL, 0, NULL, 0, iPrivKeyContext,
141  iKeyWrapContext );
143  &mechanismInfo, MECHANISM_PRIVATEKEYWRAP_PKCS8 );
144  if( cryptStatusOK( status ) )
145  privKeyDataSize = mechanismInfo.wrappedDataLength;
146  clearMechanismInfo( &mechanismInfo );
147  if( cryptStatusError( status ) )
148  return( status );
149  if( ( keyObjectInfo->data = clAlloc( "setItemFunction", \
150  64 + privKeyDataSize ) ) == NULL )
151  return( CRYPT_ERROR_MEMORY );
152  keyObjectInfo->dataSize = 64 + privKeyDataSize;
153 
154  /* Calculate the size of the key-derivation information */
155  pbeInfoDataSize = ( int ) sizeofObject( keyObjectInfo->saltSize ) + \
156  sizeofShortInteger( keyObjectInfo->iterations );
157 
158  /* Write the key-derivation information */
159  sMemOpen( &stream, ( void * ) keyObjectInfo->data,
160  keyObjectInfo->dataSize );
161  writeSequence( &stream,
163  ( int ) sizeofObject( pbeInfoDataSize ) );
165  writeSequence( &stream, pbeInfoDataSize );
166  writeOctetString( &stream, keyObjectInfo->salt, keyObjectInfo->saltSize,
167  DEFAULT_TAG );
168  writeShortInteger( &stream, keyObjectInfo->iterations, DEFAULT_TAG );
169  status = writeOctetStringHole( &stream, privKeyDataSize, DEFAULT_TAG );
170  if( cryptStatusError( status ) )
171  {
172  sMemClose( &stream );
173  return( status );
174  }
175  headerSize = stell( &stream );
176  ENSURES( rangeCheck( headerSize, privKeyDataSize,
177  keyObjectInfo->dataSize ) );
178 
179  /* Insert the wrapped key into the stream buffer */
180  status = sMemGetDataBlockRemaining( &stream, &privKeyData,
181  &privKeyDataSize );
182  if( cryptStatusError( status ) )
183  {
184  sMemClose( &stream );
185  return( status );
186  }
187  setMechanismWrapInfo( &mechanismInfo, privKeyData, privKeyDataSize,
188  NULL, 0, iPrivKeyContext, iKeyWrapContext );
190  &mechanismInfo, MECHANISM_PRIVATEKEYWRAP_PKCS8 );
191  if( cryptStatusOK( status ) )
192  {
193  keyObjectInfo->dataSize = headerSize + \
194  mechanismInfo.wrappedDataLength;
195  keyObjectInfo->payloadOffset = headerSize;
196  keyObjectInfo->payloadSize = mechanismInfo.wrappedDataLength;
197  }
198  clearMechanismInfo( &mechanismInfo );
199  if( cryptStatusError( status ) )
200  {
201  sMemClose( &stream );
202  return( status );
203  }
204  sMemDisconnect( &stream );
206  checkObjectEncoding( keyObjectInfo->data, \
207  keyObjectInfo->dataSize ) ) );
208 
209  return( CRYPT_OK );
210  }
211 
212 /* Write a certificate. PKCS #12 generally only stores the individual
213  certificate that's associated with the private key rather than a complete
214  certificate chain, so we only add the leaf certificate rather than all of
215  the certificates in the chain (that is, in theory it's possible to stuff
216  all of the certificates in the chain into the keyset, but since PKCS #12
217  has no way of identifying or indexing them there's not much that anything
218  can do with them even if they're present) */
219 
221 static int writeCertificate( INOUT PKCS12_OBJECT_INFO *certObjectInfo,
223  {
225  int status;
226 
227  assert( isWritePtr( certObjectInfo, sizeof( PKCS12_OBJECT_INFO ) ) );
228 
229  REQUIRES( isHandleRangeValid( cryptHandle ) );
230 
231  /* Select the leaf certificate */
232  status = krnlSendMessage( cryptHandle, IMESSAGE_SETATTRIBUTE,
235  if( cryptStatusError( status ) )
236  return( status );
237 
238  /* Allocate storage for the encoded certificate data */
239  setMessageData( &msgData, NULL, 0 );
240  status = krnlSendMessage( cryptHandle, IMESSAGE_CRT_EXPORT, &msgData,
242  if( cryptStatusError( status ) )
243  return( status );
244  if( ( certObjectInfo->data = clAlloc( "setItemFunction", \
245  msgData.length ) ) == NULL )
246  return( CRYPT_ERROR_MEMORY );
247 
248  /* Export the certificate */
249  msgData.data = ( void * ) certObjectInfo->data;
250  status = krnlSendMessage( cryptHandle, IMESSAGE_CRT_EXPORT, &msgData,
252  if( cryptStatusError( status ) )
253  {
254  clFree( "setItemFunction", ( void * ) certObjectInfo->data );
255  certObjectInfo->data = NULL;
256 
257  return( status );
258  }
259  certObjectInfo->dataSize = msgData.length;
260 
261  /* Since we've just created the data object, the payload is identical to
262  the data */
263  certObjectInfo->payloadSize = certObjectInfo->dataSize;
264  certObjectInfo->payloadOffset = 0;
265 
266  return( CRYPT_OK );
267  }
268 
269 /****************************************************************************
270 * *
271 * Write a Keyset *
272 * *
273 ****************************************************************************/
274 
275 /* Write a PKCS #12 item ("safeBag"). We can't write this directly to the
276  output but have to buffer it via an intermediate stream so that we can
277  MAC it */
278 
279 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
280 static int writeMacItem( INOUT STREAM *stream,
281  const PKCS12_INFO *pkcs12info,
282  const BOOLEAN isPrivateKey,
283  const BOOLEAN macData )
284  {
285  const PKCS12_OBJECT_INFO *pkcs12objectInfo = \
286  isPrivateKey ? &pkcs12info->keyInfo : &pkcs12info->certInfo;
287  STREAM memStream;
288  BYTE objectHeaderBuffer[ 256 + 8 ], idBuffer[ 256 + 8 ];
289  const int idDataSize = ( int ) \
291  sizeofObject( \
292  sizeofObject( 1 ) ) );
293  const int labelDataSize = ( int ) \
295  sizeofObject( \
296  sizeofObject( pkcs12info->labelLength * 2 ) ) );
297  const int attrDataSize = ( int ) \
298  ( sizeofObject( idDataSize ) + \
299  sizeofObject( labelDataSize ) );
300  int objectHeaderSize = DUMMY_INIT, idSize = DUMMY_INIT, i, j, status;
301 
302  assert( isWritePtr( stream, sizeof( STREAM ) ) );
303  assert( isReadPtr( pkcs12info, sizeof( PKCS12_INFO ) ) );
304 
305  /* Write the object header to a buffer where it can be MACed */
306  sMemOpen( &memStream, objectHeaderBuffer, 256 );
307  if( isPrivateKey )
308  {
309  status = writeNonCMSheader( &memStream, OID_PKCS12_SHROUDEDKEYBAG,
311  pkcs12objectInfo->dataSize, attrDataSize );
312  }
313  else
314  {
315  writeNonCMSheader( &memStream, OID_PKCS12_CERTBAG,
316  sizeofOID( OID_PKCS12_CERTBAG ), ( int ) \
318  sizeofObject( \
319  sizeofObject( pkcs12objectInfo->dataSize ) ) ),
320  attrDataSize );
321  writeOID( &memStream, OID_PKCS9_X509CERTIFICATE );
322  writeConstructed( &memStream, ( int ) \
323  sizeofObject( pkcs12objectInfo->dataSize ), 0 );
324  status = writeOctetStringHole( &memStream,
325  pkcs12objectInfo->dataSize, DEFAULT_TAG );
326  }
327  if( cryptStatusOK( status ) )
328  objectHeaderSize = stell( &memStream );
329  sMemDisconnect( &memStream );
330  if( cryptStatusError( status ) )
331  return( status );
332 
333  /* Write the object header and data to the keyset */
334  swrite( stream, objectHeaderBuffer, objectHeaderSize );
335  status = swrite( stream, pkcs12objectInfo->data,
336  pkcs12objectInfo->dataSize );
337  if( cryptStatusError( status ) )
338  return( status );
339 
340  /* Mac the payload data if necessary (we don't have to perform the
341  MACing if we're performing a dummy write to a null stream) */
342  if( macData )
343  {
344  status = krnlSendMessage( pkcs12info->iMacContext, IMESSAGE_CTX_HASH,
345  objectHeaderBuffer, objectHeaderSize );
346  if( cryptStatusOK( status ) )
347  {
348  status = krnlSendMessage( pkcs12info->iMacContext,
350  ( MESSAGE_CAST ) pkcs12objectInfo->data,
351  pkcs12objectInfo->dataSize );
352  }
353  if( cryptStatusError( status ) )
354  return( status );
355  }
356 
357  /* Write the item's ID and label. These are supposedly optional, but
358  some apps will break if they're not present. We have to keep the ID
359  short (rather than using, say, a keyID) because some apps assume that
360  it's a 32-bit int or something similar. In addition apps seem to
361  change this value at random (Windows changes it to a GUID, Mozilla/
362  NSS changes it to a SHA-1 hash) so it's pretty much meaningless
363  anyway */
364  sMemOpen( &memStream, idBuffer, 256 );
365  writeSet( &memStream, attrDataSize );
366  writeSequence( &memStream, idDataSize );
367  writeOID( &memStream, OID_PKCS9_LOCALKEYID );
368  writeSet( &memStream, sizeofObject( 1 ) );
369  writeOctetStringHole( &memStream, 1, DEFAULT_TAG );
370  sputc( &memStream, 1 ); /* ID, fixed at 0x01 for a single key */
371  writeSequence( &memStream, labelDataSize );
372  writeOID( &memStream, OID_PKCS9_FRIENDLYNAME );
373  writeSet( &memStream, ( int ) sizeofObject( pkcs12info->labelLength * 2 ) );
374  status = writeGenericHole( &memStream, pkcs12info->labelLength * 2,
375  BER_STRING_BMP );
376  for( i = 0, j = 0; i < pkcs12info->labelLength && \
377  i < CRYPT_MAX_TEXTSIZE; i++ )
378  {
379  /* Convert the ASCII string into a BMP string */
380  sputc( &memStream, 0 );
381  status = sputc( &memStream, pkcs12info->label[ i ] );
382  }
383  ENSURES( i < CRYPT_MAX_TEXTSIZE );
384  if( cryptStatusOK( status ) )
385  idSize = stell( &memStream );
386  sMemDisconnect( &memStream );
387  if( cryptStatusError( status ) )
388  return( status );
389  status = swrite( stream, idBuffer, idSize );
390  if( cryptStatusError( status ) )
391  return( status );
392 
393  /* Mac the attribute data if necessary (we don't have to perform the
394  MACing if we're performing a dummy write to a null stream) */
395  if( macData )
396  {
397  status = krnlSendMessage( pkcs12info->iMacContext,
398  IMESSAGE_CTX_HASH, idBuffer, idSize );
399  if( cryptStatusError( status ) )
400  return( status );
401  }
402 
403  return( CRYPT_OK );
404  }
405 
406 /* Flush a PKCS #12 collection to a stream */
407 
408 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
409 int pkcs12Flush( INOUT STREAM *stream,
410  IN_ARRAY( noPkcs12objects ) const PKCS12_INFO *pkcs12info,
411  IN_LENGTH_SHORT const int noPkcs12objects )
412  {
413  STREAM memStream;
414  BYTE objectHeaderBuffer[ 32 + 8 ];
415  BOOLEAN privateKeyPresent = FALSE;
416  const int macDataSize = sizeofMacData( pkcs12info );
417  int safeDataSize = DUMMY_INIT, authSafeDataSize;
418  int objectHeaderSize = DUMMY_INIT, i, status = CRYPT_OK;
419 
420  assert( isWritePtr( stream, sizeof( STREAM ) ) );
421  assert( isReadPtr( pkcs12info, \
422  sizeof( PKCS12_INFO ) * noPkcs12objects ) );
423 
424  REQUIRES( noPkcs12objects >= 1 && \
425  noPkcs12objects < MAX_INTLENGTH_SHORT );
426 
427  /* Determine the overall size of the collection of objects */
428  sMemNullOpen( &memStream );
429  for( i = 0; i < noPkcs12objects && i < FAILSAFE_ITERATIONS_MED; i++ )
430  {
431  if( pkcs12info[ i ].keyInfo.dataSize > 0 )
432  {
433  privateKeyPresent = TRUE;
434  status = writeMacItem( &memStream, pkcs12info, TRUE, FALSE );
435  if( cryptStatusError( status ) )
436  break;
437  }
438  if( pkcs12info[ i ].certInfo.dataSize > 0 )
439  {
440  status = writeMacItem( &memStream, pkcs12info, FALSE, FALSE );
441  if( cryptStatusError( status ) )
442  break;
443  }
444  }
445  ENSURES( i < FAILSAFE_ITERATIONS_MED );
446  if( cryptStatusOK( status ) )
447  safeDataSize = stell( &memStream );
448  sMemClose( &memStream );
449  if( cryptStatusError( status ) )
450  return( status );
451  if( !privateKeyPresent )
452  {
453  /* If there's no data present, let the caller know that the keyset
454  is empty */
455  return( OK_SPECIAL );
456  }
457  authSafeDataSize = ( int ) \
458  sizeofObject( \
459  sizeofObject( \
460  sizeofOID( OID_CMS_DATA ) + \
461  sizeofObject( \
462  sizeofObject( sizeofObject( safeDataSize ) ) ) ) );
463 
464  /* Write the outermost (authSafe) layer of cruft */
465  writeSequence( stream, ( int ) \
466  sizeofShortInteger( 3 ) + \
467  sizeofObject( \
468  sizeofOID( OID_CMS_DATA ) + \
469  sizeofObject( \
470  sizeofObject( authSafeDataSize ) ) ) + \
471  sizeofObject( macDataSize ) );
472  writeShortInteger( stream, 3, DEFAULT_TAG );
473  status = writeCMSheader( stream, OID_CMS_DATA, sizeofOID( OID_CMS_DATA ),
474  authSafeDataSize, TRUE );
475  if( cryptStatusError( status ) )
476  return( status );
477 
478  /* Write and MAC the next layer (safe) of cruft. We have to do this via
479  an intermediate memory stream so that we can MAC the data before we
480  write it to the keyset */
481  sMemOpen( &memStream, objectHeaderBuffer, 32 );
482  writeSequence( &memStream, ( int ) \
483  sizeofObject( \
484  sizeofOID( OID_CMS_DATA ) + \
485  sizeofObject( \
486  sizeofObject( sizeofObject( safeDataSize ) ) ) ) );
487  status = writeCMSheader( &memStream, OID_CMS_DATA,
489  sizeofObject( safeDataSize ), TRUE );
490  if( cryptStatusOK( status ) )
491  status = writeSequence( &memStream, safeDataSize );
492  if( cryptStatusOK( status ) )
493  objectHeaderSize = stell( &memStream );
494  sMemDisconnect( &memStream );
495  if( cryptStatusError( status ) )
496  return( status );
497  swrite( stream, objectHeaderBuffer, objectHeaderSize );
498  status = krnlSendMessage( pkcs12info->iMacContext,
499  IMESSAGE_CTX_HASH, objectHeaderBuffer,
500  objectHeaderSize );
501  if( cryptStatusError( status ) )
502  return( status );
503 
504  /* Write the individual objects */
505  for( i = 0; i < noPkcs12objects; i++ )
506  {
507  if( pkcs12info[ i ].keyInfo.dataSize > 0 )
508  {
509  status = writeMacItem( stream, pkcs12info, TRUE, TRUE );
510  if( cryptStatusError( status ) )
511  return( status );
512  }
513  if( pkcs12info[ i ].certInfo.dataSize > 0 )
514  {
515  status = writeMacItem( stream, pkcs12info, FALSE, TRUE );
516  if( cryptStatusError( status ) )
517  return( status );
518  }
519  }
520 
521  /* Write the MAC data at the end of the keyset */
522  status = writeMacData( stream, pkcs12info );
523  if( cryptStatusError( status ) )
524  return( status );
525 
526  return( sflush( stream ) );
527  }
528 
529 /****************************************************************************
530 * *
531 * Add a Key *
532 * *
533 ****************************************************************************/
534 
535 /* Add an item to the PKCS #12 keyset. PKCS #12's braindamaged format
536  severly restricts what we can allow in terms of keyset updates. Since
537  there's only a single KEK used for both the private-key wrap and the
538  overall MAC of the data, we can't store more than one private key. In
539  addition because of the lack of any useful indexing information there's
540  no way to match anything to anything else, so we have to assume that
541  a certificate being added belongs with the already-present private key.
542  To handle all of these constraints we only store a single private key and
543  only allow a certificate to be added either alongside or after the
544  private key has been added */
545 
547 static int setItemFunction( INOUT KEYSET_INFO *keysetInfoPtr,
548  IN_HANDLE const CRYPT_HANDLE cryptHandle,
549  IN_ENUM( KEYMGMT_ITEM ) \
550  const KEYMGMT_ITEM_TYPE itemType,
551  IN_BUFFER_OPT( passwordLength ) const char *password,
553  IN_FLAGS( KEYMGMT ) const int flags )
554  {
555  CRYPT_CONTEXT iKeyWrapContext;
556  PKCS12_INFO *pkcs12info = keysetInfoPtr->keyData;
557  PKCS12_OBJECT_INFO *keyObjectInfo = &pkcs12info->keyInfo;
558  PKCS12_OBJECT_INFO *certObjectInfo = &pkcs12info->certInfo;
559  BOOLEAN certPresent = FALSE, contextPresent;
560  BOOLEAN pkcs12keyPresent = ( keyObjectInfo->dataSize > 0 ) ? TRUE : FALSE;
561  BOOLEAN wrapContextInitialised = FALSE;
562  int value, status;
563 
564  assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
565  assert( isWritePtr( pkcs12info, \
566  sizeof( PKCS12_INFO ) * \
567  keysetInfoPtr->keyDataNoObjects ) );
568 
569  REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
570  keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS12 );
571  REQUIRES( isHandleRangeValid( cryptHandle ) );
572  REQUIRES( itemType == KEYMGMT_ITEM_PUBLICKEY || \
573  itemType == KEYMGMT_ITEM_PRIVATEKEY );
574  REQUIRES( ( password == NULL && passwordLength == 0 ) || \
575  ( password != NULL && \
576  passwordLength >= MIN_NAME_LENGTH && \
577  passwordLength < MAX_ATTRIBUTE_SIZE ) );
578  REQUIRES( ( itemType == KEYMGMT_ITEM_PUBLICKEY && \
579  password == NULL && passwordLength == 0 ) || \
580  ( itemType == KEYMGMT_ITEM_PRIVATEKEY && \
581  password != NULL && passwordLength != 0 ) );
582  REQUIRES( flags == KEYMGMT_FLAG_NONE );
583 
584  /* If there's already a key and certificate present then we can't add
585  anything else. This check also catches the (invalid) case of a
586  certificate being present without a corresponding private key */
587  if( certObjectInfo->dataSize > 0 )
588  {
591  "No more room in keyset to add this item" ) );
592  }
593 
594  /* Check the object and extract any information that we may need from
595  it */
596  status = krnlSendMessage( cryptHandle, IMESSAGE_CHECK, NULL,
598  if( cryptStatusOK( status ) )
599  {
600  int algorithm; /* int vs.enum */
601 
602  status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE,
603  &algorithm, CRYPT_CTXINFO_ALGO );
604  if( cryptStatusOK( status ) && algorithm != CRYPT_ALGO_RSA )
605  {
608  "PKCS #12 keysets can only store RSA private keys "
609  "and certificates" ) );
610  }
611  }
612  if( cryptStatusError( status ) )
613  {
614  return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
615  CRYPT_ARGERROR_NUM1 : status );
616  }
617  contextPresent = cryptStatusOK( \
618  krnlSendMessage( cryptHandle, IMESSAGE_CHECK, NULL,
620  TRUE : FALSE;
621 
622  /* If there's a certificate present, make sure that it's something that
623  can be stored. We don't treat the wrong type as an error since we
624  can still store the public/private key components even if we don't
625  store the certificate */
626  status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE,
627  &value, CRYPT_CERTINFO_CERTTYPE );
628  if( cryptStatusOK( status ) && \
629  ( value == CRYPT_CERTTYPE_CERTIFICATE || \
630  value == CRYPT_CERTTYPE_CERTCHAIN ) )
631  {
632  certPresent = TRUE;
633 
634  /* If the certificate isn't signed then we can't store it in this
635  state */
636  status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE,
637  &value, CRYPT_CERTINFO_IMMUTABLE );
638  if( cryptStatusError( status ) || !value )
639  {
642  "Certificate being added is incomplete (unsigned)" ) );
643  }
644 
645  /* We can't add a certificate unless there's already a key present.
646  Since PKCS #12 doesn't store any indexing information we have no
647  idea whether the two actually belong together, so we just have to
648  hope for the best */
649  if( !pkcs12keyPresent )
650  {
653  "No key present that corresponds to the certificate "
654  "being added" ) );
655  }
656  }
657  else
658  {
659  /* If we're trying to add a standalone key and there's already one
660  present then we can't add another one */
661  if( pkcs12keyPresent )
662  {
665  "No more room in keyset to add this item" ) );
666  }
667  }
668 
669  /* PKCS #12 keysets can't store public keys, only private keys and
670  certifiates */
671  if( itemType == KEYMGMT_ITEM_PUBLICKEY && !certPresent )
672  {
675  "PKCS #12 keysets can only store private keys and "
676  "certificates, not public keys" ) );
677  }
678 
679  /* At this point we're either storing a certificate or a private key
680  (with an optional certificate attached) */
681  ENSURES( ( itemType == KEYMGMT_ITEM_PUBLICKEY && certPresent ) || \
682  ( itemType == KEYMGMT_ITEM_PRIVATEKEY && contextPresent ) );
683 
684  /* If we're adding a private key, make sure that there's a password
685  present. Conversely, if there's a password present make sure that
686  we're adding a private key */
687  if( pkcs12keyPresent )
688  {
689  /* We're adding a certificate, there can't be a password present.
690  Some PKCS #12 implementations encrypt public certificates for no
691  adequately explained reason, we always store them as plaintext
692  since they are, after all, *public* certificates */
693  if( password != NULL )
694  return( CRYPT_ARGERROR_NUM1 );
695  }
696  else
697  {
698  /* We're adding a private key, there must be a password present */
699  if( password == NULL )
700  return( CRYPT_ARGERROR_STR1 );
701  }
702 
703  /* Get what little index information PKCS #12 stores with a key */
704  if( !pkcs12keyPresent && contextPresent )
705  {
707 
708  setMessageData( &msgData, pkcs12info->label, CRYPT_MAX_TEXTSIZE );
709  status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
710  &msgData, CRYPT_CTXINFO_LABEL );
711  if( cryptStatusError( status ) )
712  return( status );
713  pkcs12info->labelLength = msgData.length;
714  }
715 
716  /* Write the certificate if necessary. We do this one first because
717  it's the easiest to back out of */
718  if( certPresent )
719  {
720  /* We're ready to go, lock the object for our exclusive use */
721  status = krnlSendMessage( cryptHandle, IMESSAGE_SETATTRIBUTE,
723  CRYPT_IATTRIBUTE_LOCKED );
724  if( cryptStatusError( status ) )
725  return( status );
726 
727  status = writeCertificate( certObjectInfo, cryptHandle );
728  ( void ) krnlSendMessage( cryptHandle, IMESSAGE_SETATTRIBUTE,
730  CRYPT_IATTRIBUTE_LOCKED );
731  if( cryptStatusError( status ) )
732  {
733  retExt( status,
734  ( status, KEYSET_ERRINFO,
735  "Couldn't extract certificate data from "
736  "certificate" ) );
737  }
738  pkcs12info->flags |= PKCS12_FLAG_CERT;
739 
740  /* If there's already a key present, return now */
741  if( pkcs12keyPresent )
742  return( CRYPT_OK );
743  }
744 
745  /* Create the key wrap context and the MAC context (if necessary) from
746  the password */
747  status = createPkcs12KeyWrapContext( keyObjectInfo,
748  keysetInfoPtr->ownerHandle,
749  password, passwordLength,
750  &iKeyWrapContext, TRUE );
751  if( cryptStatusOK( status ) )
752  {
753  wrapContextInitialised = TRUE;
754  if( !pkcs12info->macInitialised )
755  {
756  status = createPkcs12MacContext( pkcs12info,
757  keysetInfoPtr->ownerHandle,
758  password, passwordLength,
759  &pkcs12info->iMacContext, TRUE );
760  }
761  }
762  if( cryptStatusError( status ) )
763  {
764  pkcs12freeEntry( pkcs12info );
765  if( wrapContextInitialised )
766  krnlSendNotifier( iKeyWrapContext, IMESSAGE_DECREFCOUNT );
767  retExt( status,
768  ( status, KEYSET_ERRINFO,
769  "Couldn't create session/MAC key to secure private "
770  "key" ) );
771  }
772  pkcs12info->macInitialised = TRUE;
773 
774  /* Write the encrypted and MACed private key */
775  status = writePrivateKey( keyObjectInfo, cryptHandle,
776  iKeyWrapContext );
777  krnlSendNotifier( iKeyWrapContext, IMESSAGE_DECREFCOUNT );
778  if( cryptStatusError( status ) )
779  {
780  pkcs12freeEntry( pkcs12info );
781  retExt( status,
782  ( status, KEYSET_ERRINFO,
783  "Couldn't write wrapped private key data" ) );
784  }
785  pkcs12info->flags |= PKCS12_FLAG_PRIVKEY;
786 
787  return( CRYPT_OK );
788  }
789 
790 /****************************************************************************
791 * *
792 * Keyset Access Routines *
793 * *
794 ****************************************************************************/
795 
797 int initPKCS12set( INOUT KEYSET_INFO *keysetInfoPtr )
798  {
799  assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
800 
801  REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
802  keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS12 );
803 
804  /* Set the access method pointers */
805  keysetInfoPtr->setItemFunction = setItemFunction;
806 
807  return( CRYPT_OK );
808  }
809 #endif /* USE_PKCS12 */