cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
pkcs15_adpb.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib PKCS #15 Public-key Add Interface *
4 * Copyright Peter Gutmann 1996-2007 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "asn1.h"
11  #include "keyset.h"
12  #include "pkcs15.h"
13 #else
14  #include "crypt.h"
15  #include "enc_dec/asn1.h"
16  #include "keyset/keyset.h"
17  #include "keyset/pkcs15.h"
18 #endif /* Compiler-specific includes */
19 
20 #ifdef USE_PKCS15
21 
22 /* Define the following to use the corrected PKCS #15 v1.2 form for
23  ObjectValue.direct tagging rather than the original erroneous v1.1
24  form. Note that this will break backwards compatibility for cryptlib
25  versions before 3.4.0, however 3.4.0 also introduces AuthEncData so this
26  seems like a good time to make the changeover for the tagging as well */
27 
28 #define USE_PKCS15V12_FORM
29 
30 /****************************************************************************
31 * *
32 * Utility Functions *
33 * *
34 ****************************************************************************/
35 
36 /* Calculate the size of and if necessary allocate storage for public-key
37  and certificate data */
38 
39 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
40 static int calculatePubkeyStorage( const PKCS15_INFO *pkcs15infoPtr,
41  OUT_PTR void **newPubKeyDataPtr,
42  OUT_LENGTH_SHORT_Z int *newPubKeyDataSize,
43  IN_LENGTH_SHORT const int pubKeySize,
45  IN_LENGTH_SHORT const int extraDataSize )
46  {
47  void *newPubKeyData;
48 
49  assert( isReadPtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
50  assert( isWritePtr( newPubKeyDataPtr, sizeof( void * ) ) );
51  assert( isWritePtr( newPubKeyDataSize, sizeof( int ) ) );
52 
53  REQUIRES( pubKeySize > 0 && pubKeySize < MAX_INTLENGTH_SHORT );
54  REQUIRES( pubKeyAttributeSize > 0 && \
55  pubKeyAttributeSize < MAX_INTLENGTH_SHORT );
56  REQUIRES( extraDataSize >= 0 && extraDataSize < MAX_INTLENGTH_SHORT );
57 
58  /* Calculate the new private-key data size */
59  *newPubKeyDataSize = sizeofObject( \
60  pubKeyAttributeSize + \
61  sizeofObject( \
62  sizeofObject( \
63  sizeofObject( pubKeySize ) + \
64  extraDataSize ) ) );
65  ENSURES( *newPubKeyDataSize > 0 && *newPubKeyDataSize < MAX_INTLENGTH );
66 
67  /* If the new data will fit into the existing storage, we're done */
68  if( *newPubKeyDataSize <= pkcs15infoPtr->pubKeyDataSize )
69  return( CRYPT_OK );
70 
71  /* Allocate storage for the new data */
72  newPubKeyData = clAlloc( "calculatePubkeyStorage", *newPubKeyDataSize );
73  if( newPubKeyData == NULL )
74  return( CRYPT_ERROR_MEMORY );
75  *newPubKeyDataPtr = newPubKeyData;
76 
77  return( CRYPT_OK );
78  }
79 
80 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
81 static int calculateCertStorage( const PKCS15_INFO *pkcs15infoPtr,
82  OUT_PTR void **newCertDataPtr,
83  OUT_LENGTH_SHORT_Z int *newCertDataSize,
85  IN_LENGTH_SHORT const int certSize )
86  {
87  void *newCertData;
88 
89  assert( isReadPtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
90  assert( isWritePtr( newCertDataPtr, sizeof( void * ) ) );
91  assert( isWritePtr( newCertDataSize, sizeof( int ) ) );
92 
93  REQUIRES( certAttributeSize > 0 && \
94  certAttributeSize < MAX_INTLENGTH_SHORT );
95  REQUIRES( certSize > 0 && certSize < MAX_INTLENGTH_SHORT );
96 
97  /* Calculate the new certificate data size */
98 #ifdef USE_PKCS15V12_FORM
99  *newCertDataSize = sizeofObject( certAttributeSize + \
100  sizeofObject( \
101  sizeofObject( \
102  sizeofObject( certSize ) ) ) );
103 #else
104  *newCertDataSize = sizeofObject( certAttributeSize + \
105  sizeofObject( \
106  sizeofObject( certSize ) ) );
107 #endif /* USE_PKCS15V12_FORM */
108  ENSURES( *newCertDataSize > 0 && *newCertDataSize < MAX_INTLENGTH );
109 
110  /* If the new data will fit into the existing storage, we're done */
111  if( *newCertDataSize <= pkcs15infoPtr->certDataSize )
112  return( CRYPT_OK );
113 
114  /* Allocate storage for the new data */
115  newCertData = clAlloc( "calculateCertStorage", *newCertDataSize );
116  if( newCertData == NULL )
117  return( CRYPT_ERROR_MEMORY );
118  *newCertDataPtr = newCertData;
119 
120  return( CRYPT_OK );
121  }
122 
123 /* Delete the public-key entry for a personality, used when we're replacing
124  the pubkey with a certificate */
125 
126 STDC_NONNULL_ARG( ( 1 ) ) \
127 static void deletePubKey( INOUT PKCS15_INFO *pkcs15infoPtr )
128  {
129  assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
130 
131  zeroise( pkcs15infoPtr->pubKeyData, pkcs15infoPtr->pubKeyDataSize );
132  clFree( "deletePubKey", pkcs15infoPtr->pubKeyData );
133  pkcs15infoPtr->pubKeyData = NULL;
134  pkcs15infoPtr->pubKeyDataSize = 0;
135  }
136 
137 /* Replace existing public-key or certificate data with updated
138  information */
139 
140 STDC_NONNULL_ARG( ( 1, 2 ) ) \
141 static void replacePubkeyData( INOUT PKCS15_INFO *pkcs15infoPtr,
142  IN_BUFFER( newPubKeyDataSize ) \
143  const void *newPubKeyData,
144  IN_LENGTH_SHORT_MIN( 16 ) \
145  const int newPubKeyDataSize,
146  IN_LENGTH_SHORT const int newPubKeyOffset )
147  {
148  assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
149  assert( isReadPtr( newPubKeyData, newPubKeyDataSize ) );
150 
151  REQUIRES_V( newPubKeyDataSize >= 16 && \
152  newPubKeyDataSize < MAX_INTLENGTH_SHORT );
153  REQUIRES_V( newPubKeyOffset > 0 && \
154  newPubKeyOffset < newPubKeyDataSize && \
155  newPubKeyOffset < MAX_INTLENGTH_SHORT );
156 
157  /* If we've allocated new storage for the data rather than directly
158  replacing the existing entry, free the existing entry and replace it
159  with the new one */
160  if( newPubKeyData != pkcs15infoPtr->pubKeyData )
161  {
162  if( pkcs15infoPtr->pubKeyData != NULL )
163  {
164  zeroise( pkcs15infoPtr->pubKeyData,
165  pkcs15infoPtr->pubKeyDataSize );
166  clFree( "replacePubkeyData", pkcs15infoPtr->pubKeyData );
167  }
168  pkcs15infoPtr->pubKeyData = ( void * ) newPubKeyData;
169  }
170 
171  /* Update the size information */
172  pkcs15infoPtr->pubKeyDataSize = newPubKeyDataSize;
173  pkcs15infoPtr->pubKeyOffset = newPubKeyOffset;
174  }
175 
176 STDC_NONNULL_ARG( ( 1, 2 ) ) \
177 static void replaceCertData( INOUT PKCS15_INFO *pkcs15infoPtr,
178  IN_BUFFER( newCertDataSize ) \
179  const void *newCertData,
180  IN_LENGTH_SHORT_MIN( 16 ) \
181  const int newCertDataSize,
182  IN_LENGTH_SHORT const int newCertOffset )
183  {
184  assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
185  assert( isReadPtr( newCertData, newCertDataSize ) );
186 
187  REQUIRES_V( newCertDataSize >= 16 && \
188  newCertDataSize < MAX_INTLENGTH_SHORT );
189  REQUIRES_V( newCertOffset > 0 && \
190  newCertOffset < newCertDataSize && \
191  newCertOffset < MAX_INTLENGTH_SHORT );
192 
193  /* If we've allocated new storage for the data rather than directly
194  replacing the existing entry, free the existing entry and replace it
195  with the new one */
196  if( newCertData != pkcs15infoPtr->certData )
197  {
198  if( pkcs15infoPtr->certData != NULL )
199  {
200  zeroise( pkcs15infoPtr->certData, pkcs15infoPtr->certDataSize );
201  clFree( "replaceCertData", pkcs15infoPtr->certData );
202  }
203  pkcs15infoPtr->certData = ( void * ) newCertData;
204  }
205 
206  /* Update the size information */
207  pkcs15infoPtr->certDataSize = newCertDataSize;
208  pkcs15infoPtr->certOffset = newCertOffset;
209  }
210 
211 /****************************************************************************
212 * *
213 * Add a Certificate *
214 * *
215 ****************************************************************************/
216 
217 /* Add a certificate to a PKCS #15 collection, updating affected public and
218  private key attributes as required */
219 
220 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 6 ) ) \
221 int pkcs15AddCert( INOUT PKCS15_INFO *pkcs15infoPtr,
224  const void *privKeyAttributes,
226  IN_ENUM( CERTADD ) const CERTADD_TYPE certAddType,
228  {
230  STREAM stream;
232  void *newCertData = pkcs15infoPtr->certData;
233  void *newPrivKeyData = pkcs15infoPtr->privKeyData;
234  int newCertDataSize = DUMMY_INIT, certInfoSize = DUMMY_INIT;
236  int newCertOffset = DUMMY_INIT, certAttributeSize;
237  int subType = PKCS15_SUBTYPE_NORMAL, keyTypeTag, status;
238 
239  assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
240  assert( ( certAddType == CERTADD_UPDATE_EXISTING && \
241  isReadPtr( privKeyAttributes, privKeyAttributeSize ) ) || \
242  ( ( certAddType == CERTADD_NORMAL || \
243  certAddType == CERTADD_STANDALONE_CERT ) && \
244  privKeyAttributes == NULL && privKeyAttributeSize == 0 ) );
245 
246  REQUIRES( isHandleRangeValid( iCryptCert ) );
247  REQUIRES( ( certAddType == CERTADD_UPDATE_EXISTING && \
248  privKeyAttributes != NULL && \
249  privKeyAttributeSize > 0 && \
250  privKeyAttributeSize < MAX_INTLENGTH_SHORT ) || \
251  ( ( certAddType == CERTADD_NORMAL || \
252  certAddType == CERTADD_STANDALONE_CERT ) && \
253  privKeyAttributes == NULL && privKeyAttributeSize == 0 ) );
254  REQUIRES( certAddType > CERTADD_NONE && certAddType < CERTADD_LAST );
255  REQUIRES( errorInfo != NULL );
256 
257  /* Get the tag for encoding the key data */
258  status = getKeyTypeTag( iCryptCert, CRYPT_ALGO_NONE, &keyTypeTag );
259  if( cryptStatusError( status ) )
260  return( status );
261 
262  /* If we've been passed a standalone certificate it has to be
263  implicitly trusted in order to be added. We don't perform this check
264  if this is a storage object for a hardware device, which acts as a
265  generic information store with no restrictions on what can be
266  stored */
267  if( certAddType == CERTADD_STANDALONE_CERT )
268  {
269  int value;
270 
271  status = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE,
273  if( cryptStatusError( status ) || !value )
274  {
276  ( CRYPT_ARGERROR_NUM1, errorInfo,
277  "Only a trusted certificate can be added as a "
278  "standalone certificate" ) );
279  }
280 
281  /* Set the personality type to certificate-only */
282  subType = PKCS15_SUBTYPE_CERT;
283  }
284 
285  /* Write the certificate attributes */
286  status = writeCertAttributes( certAttributes, KEYATTR_BUFFER_SIZE,
287  &certAttributeSize, pkcs15infoPtr,
288  iCryptCert );
289  if( cryptStatusError( status ) )
290  {
291  retExt( status,
292  ( status, errorInfo,
293  "Couldn't write certificate attributes" ) );
294  }
295 
296  /* Find out how big the PKCS #15 data will be and allocate room for it.
297  Since adding the certificate will affect the key attributes we need
298  to rewrite the key information once we've added the certificate */
299  if( certAddType == CERTADD_UPDATE_EXISTING )
300  {
301  /* Since we're re-using pre-encoded private key data the extra
302  information is already present in encoded form so we set the
303  extraDataSize parameter to zero */
304  privKeyInfoSize = pkcs15infoPtr->privKeyDataSize - \
305  pkcs15infoPtr->privKeyOffset;
306  status = calculatePrivkeyStorage( &newPrivKeyData, &newPrivKeyDataSize,
307  pkcs15infoPtr->privKeyData,
308  pkcs15infoPtr->privKeyDataSize,
309  privKeyInfoSize,
310  privKeyAttributeSize, 0 );
311  if( cryptStatusError( status ) )
312  return( status );
313  }
314  setMessageData( &msgData, NULL, 0 );
315  status = krnlSendMessage( iCryptCert, IMESSAGE_CRT_EXPORT, &msgData,
317  if( cryptStatusOK( status ) )
318  {
319  certInfoSize = msgData.length;
320  status = calculateCertStorage( pkcs15infoPtr, &newCertData,
321  &newCertDataSize, certAttributeSize,
322  certInfoSize );
323  }
324  if( cryptStatusError( status ) )
325  {
326  if( newPrivKeyData != pkcs15infoPtr->privKeyData )
327  clFree( "addCert", newPrivKeyData );
328  return( status );
329  }
330  ANALYSER_HINT( newPrivKeyData != NULL );
331 
332  /* Write the PKCS #15 certificate data */
333  sMemOpen( &stream, newCertData, newCertDataSize );
334 #ifdef USE_PKCS15V12_FORM
335  writeSequence( &stream, certAttributeSize + \
336  sizeofObject( \
337  sizeofObject( \
338  sizeofObject( certInfoSize ) ) ) );
339  swrite( &stream, certAttributes, certAttributeSize );
340  writeConstructed( &stream, sizeofObject( \
341  sizeofObject( certInfoSize ) ),
343  writeSequence( &stream, sizeofObject( certInfoSize ) );
344  status = writeConstructed( &stream, certInfoSize, CTAG_OV_DIRECT );
345 #else
346  writeSequence( &stream, certAttributeSize + \
347  sizeofObject( sizeofObject( certInfoSize ) ) );
348  swrite( &stream, certAttributes, certAttributeSize );
349  writeConstructed( &stream, sizeofObject( certInfoSize ),
351  status = writeSequence( &stream, certInfoSize );
352 #endif /* USE_PKCS15V12_FORM */
353  if( cryptStatusOK( status ) )
354  {
355  newCertOffset = stell( &stream );
356  status = exportCertToStream( &stream, iCryptCert,
358  }
359  sMemDisconnect( &stream );
360  if( cryptStatusError( status ) )
361  {
362  /* Undo what we've done so far without changing the existing PKCS #15
363  data */
364  DEBUG_DIAG(( "Failed to set up/write certificate data" ));
365  assert( DEBUG_WARN );
366  if( newPrivKeyData != pkcs15infoPtr->privKeyData )
367  clFree( "addCert", newPrivKeyData );
368  if( newCertData != pkcs15infoPtr->certData && newCertData != NULL )
369  clFree( "addCert", newCertData );
370  retExt( status,
371  ( status, errorInfo,
372  "Couldn't write PKCS #15 certificate data" ) );
373  }
374  ENSURES( !cryptStatusError( checkObjectEncoding( newCertData, \
375  newCertDataSize ) ) );
376 
377  /* Replace the old certificate (if there is one) with the new one. If
378  it's a certificate associated with a private key we also have to
379  update the private-key attributes, which can be affected by
380  certificate information */
381  pkcs15infoPtr->type = subType;
382  replaceCertData( pkcs15infoPtr, newCertData, newCertDataSize,
383  newCertOffset );
384  if( certAddType == CERTADD_UPDATE_EXISTING )
385  {
386  updatePrivKeyAttributes( pkcs15infoPtr,
387  newPrivKeyData, newPrivKeyDataSize,
388  privKeyAttributes, privKeyAttributeSize,
389  privKeyInfoSize, keyTypeTag );
390  }
391 
392  /* The public-key data is redundant now that we've performed the update,
393  delete it */
394  if( pkcs15infoPtr->pubKeyData != NULL )
395  deletePubKey( pkcs15infoPtr );
396 
397  return( CRYPT_OK );
398  }
399 
400 /* Add a complete certificate chain to a PKCS #15 collection */
401 
402 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
403 int pkcs15AddCertChain( INOUT PKCS15_INFO *pkcs15info,
405  IN_HANDLE const CRYPT_CERTIFICATE iCryptCert,
406  INOUT ERROR_INFO *errorInfo )
407  {
408  BOOLEAN seenNonDuplicate = FALSE;
409  int iterationCount = 0, status;
410 
411  assert( isWritePtr( pkcs15info, \
412  sizeof( PKCS15_INFO ) * noPkcs15objects ) );
413 
414  REQUIRES( noPkcs15objects >= 1 && \
415  noPkcs15objects < MAX_INTLENGTH_SHORT );
416  REQUIRES( isHandleRangeValid( iCryptCert ) );
417  REQUIRES( errorInfo != NULL );
418 
419  /* See if there are certificates in the chain beyond the first one,
420  which we've already added. Getting a data not found error is OK
421  since it just means that there are no more certificates present */
422  status = krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE,
425  if( cryptStatusOK( status ) )
426  status = krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE,
429  if( cryptStatusError( status ) )
430  return( ( status == CRYPT_ERROR_NOTFOUND ) ? CRYPT_OK : status );
431 
432  /* Walk up the chain checking each certificate to see whether we need to
433  add it */
434  do
435  {
437  BYTE iAndSID[ CRYPT_MAX_HASHSIZE + 8 ];
438  int iAndSIDlength, index;
439 
440  /* Check whether this certificate is present */
441  status = getCertID( iCryptCert, CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER,
442  iAndSID, KEYID_SIZE, &iAndSIDlength );
443  if( cryptStatusError( status ) )
444  continue;
445  if( findEntry( pkcs15info, noPkcs15objects, CRYPT_IKEYID_ISSUERID,
446  iAndSID, iAndSIDlength, KEYMGMT_FLAG_NONE ) != NULL )
447  continue;
448 
449  /* We've found a certificate that isn't present yet, try and add
450  it */
451  pkcs15infoPtr = findFreeEntry( pkcs15info, noPkcs15objects, &index );
452  if( pkcs15infoPtr == NULL )
453  return( CRYPT_ERROR_OVERFLOW );
454  status = pkcs15AddCert( pkcs15infoPtr, iCryptCert, NULL, 0,
455  CERTADD_NORMAL, errorInfo );
456  if( cryptStatusOK( status ) )
457  pkcs15infoPtr->index = index;
458 
459  /* A certificate being added may already be present, however we
460  can't fail immediately because there may be further certificates
461  in the chain that can be added so we keep track of whether we've
462  successfully added at least one certificate and clear data
463  duplicate errors */
464  if( cryptStatusOK( status ) )
465  seenNonDuplicate = TRUE;
466  else
467  {
468  if( status == CRYPT_ERROR_DUPLICATE )
469  status = CRYPT_OK;
470  }
471  }
472  while( cryptStatusOK( status ) && \
476  iterationCount++ < FAILSAFE_ITERATIONS_MED );
477  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
478  if( cryptStatusOK( status ) && !seenNonDuplicate )
479  {
480  /* We reached the end of the chain without finding anything that we
481  could add, return a data duplicate error */
483  ( CRYPT_ERROR_DUPLICATE, errorInfo,
484  "Couldn't find any new certificates to add" ) );
485  }
486  return( status );
487  }
488 
489 /****************************************************************************
490 * *
491 * Add a Public Key *
492 * *
493 ****************************************************************************/
494 
495 /* Add a public key to a PKCS #15 collection */
496 
497 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 8 ) ) \
498 int pkcs15AddPublicKey( INOUT PKCS15_INFO *pkcs15infoPtr,
500  IN_BUFFER( pubKeyAttributeSize ) \
501  const void *pubKeyAttributes,
502  IN_LENGTH_SHORT const int pubKeyAttributeSize,
504  IN_LENGTH_PKC const int modulusSize,
505  const BOOLEAN isStorageObject,
506  INOUT ERROR_INFO *errorInfo )
507  {
508  const CRYPT_ATTRIBUTE_TYPE keyDataType = isStorageObject ? \
509  CRYPT_IATTRIBUTE_KEY_SPKI_PARTIAL : CRYPT_IATTRIBUTE_KEY_SPKI;
511  STREAM stream;
512  void *newPubKeyData = pkcs15infoPtr->pubKeyData;
513  int newPubKeyDataSize, newPubKeyOffset = DUMMY_INIT, pubKeySize;
514  int extraDataSize = 0, keyTypeTag, status;
515 
516  assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
517  assert( isReadPtr( pubKeyAttributes, pubKeyAttributeSize ) );
518 
519  REQUIRES( isHandleRangeValid( iCryptContext ) );
520  REQUIRES( pubKeyAttributeSize > 0 && \
521  pubKeyAttributeSize < MAX_INTLENGTH_SHORT );
522  REQUIRES( isPkcAlgo( pkcCryptAlgo ) );
523  REQUIRES( ( isEccAlgo( pkcCryptAlgo ) && \
524  modulusSize >= MIN_PKCSIZE_ECC && \
525  modulusSize <= CRYPT_MAX_PKCSIZE_ECC ) || \
526  ( !isEccAlgo( pkcCryptAlgo ) && \
527  modulusSize >= MIN_PKCSIZE && \
528  modulusSize <= CRYPT_MAX_PKCSIZE ) );
529  REQUIRES( errorInfo != NULL );
530 
531  /* Get the tag for encoding the key data */
532  status = getKeyTypeTag( CRYPT_UNUSED, pkcCryptAlgo, &keyTypeTag );
533  if( cryptStatusError( status ) )
534  return( status );
535 
536  /* Find out how big the PKCS #15 data will be and allocate room for it.
537  If it's a key metadata object then we have to read the information
538  using CRYPT_IATTRIBUTE_KEY_SPKI_PARTIAL since it's not necessarily
539  in the high state as required by CRYPT_IATTRIBUTE_KEY_SPKI because
540  the hardware may not be ready yet, but we can still fetch the stored
541  public-key data from it */
542  setMessageData( &msgData, NULL, 0 );
543  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
544  &msgData, keyDataType );
545  if( cryptStatusError( status ) )
546  return( status );
547  pubKeySize = msgData.length;
548  if( pkcCryptAlgo == CRYPT_ALGO_RSA )
549  {
550  /* RSA keys have an extra element for PKCS #11 compatibility */
551  extraDataSize = sizeofShortInteger( modulusSize );
552  }
553  status = calculatePubkeyStorage( pkcs15infoPtr, &newPubKeyData,
554  &newPubKeyDataSize, pubKeySize,
555  pubKeyAttributeSize, extraDataSize );
556  if( cryptStatusError( status ) )
557  return( status );
558 
559  /* Write the public key data */
560  sMemOpen( &stream, newPubKeyData, newPubKeyDataSize );
561  writeConstructed( &stream, pubKeyAttributeSize + \
562  sizeofObject( \
563  sizeofObject( \
564  sizeofObject( pubKeySize ) + \
565  extraDataSize ) ),
566  keyTypeTag );
567  swrite( &stream, pubKeyAttributes, pubKeyAttributeSize );
568  writeConstructed( &stream, sizeofObject( \
569  sizeofObject( pubKeySize ) + \
570  extraDataSize ),
572  writeSequence( &stream, sizeofObject( pubKeySize ) + extraDataSize );
573  status = writeConstructed( &stream, pubKeySize, CTAG_OV_DIRECT );
574  if( cryptStatusOK( status ) )
575  {
576  newPubKeyOffset = stell( &stream );
577  status = exportAttributeToStream( &stream, iCryptContext,
578  keyDataType );
579  }
580  if( cryptStatusOK( status ) && pkcCryptAlgo == CRYPT_ALGO_RSA )
581  {
582  /* When using the SPKI option for storing key components the RSA
583  components require a [1] tag since the basic (non-SPKI) option is
584  also a SEQUENCE, so if it's an RSA key we modify the tag. This is
585  easier than passing the tag requirement down through the kernel
586  call to the context. In addition RSA keys have an extra element
587  for PKCS #11 compatibility */
588  ( ( BYTE * ) newPubKeyData )[ newPubKeyOffset ] = MAKE_CTAG( 1 );
589  status = writeShortInteger( &stream, modulusSize, DEFAULT_TAG );
590  }
591  assert( stell( &stream ) == newPubKeyDataSize );
592  sMemDisconnect( &stream );
593  if( cryptStatusError( status ) )
594  {
595  DEBUG_DIAG(( "Failed to set up/write public key data" ));
596  assert( DEBUG_WARN );
597  if( newPubKeyData != pkcs15infoPtr->pubKeyData )
598  clFree( "addPublicKey", newPubKeyData );
599  retExt( status,
600  ( status, errorInfo,
601  "Couldn't write PKCS #15 public-key data" ) );
602  }
603  ENSURES( !cryptStatusError( checkObjectEncoding( newPubKeyData, \
604  newPubKeyDataSize ) ) );
605 
606  /* Replace the old data with the newly-written data */
607  replacePubkeyData( pkcs15infoPtr, newPubKeyData, newPubKeyDataSize,
608  newPubKeyOffset );
609  return( CRYPT_OK );
610  }
611 #endif /* USE_PKCS15 */