cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
pkcs15_set.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib PKCS #15 Set-item Routines *
4 * Copyright Peter Gutmann 1996-2007 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "keyset.h"
11  #include "pkcs15.h"
12 #else
13  #include "crypt.h"
14  #include "keyset/keyset.h"
15  #include "keyset/pkcs15.h"
16 #endif /* Compiler-specific includes */
17 
18 #ifdef USE_PKCS15
19 
20 /****************************************************************************
21 * *
22 * Utility Functions *
23 * *
24 ****************************************************************************/
25 
26 /* Check whether we can add anything to a PKCS #15 personality */
27 
28 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 8, 9 ) ) \
29 static int checkAddInfo( const PKCS15_INFO *pkcs15infoPtr,
31  const BOOLEAN isCertChain,
32  const BOOLEAN privkeyPresent,
33  const BOOLEAN certPresent,
35  const BOOLEAN pkcs15certPresent,
36  OUT BOOLEAN *isCertUpdate,
38  {
40  BOOLEAN unneededCert, unneededKey;
41  int status;
42 
43  assert( isReadPtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
44  assert( isWritePtr( isCertUpdate, sizeof( BOOLEAN ) ) );
45 
46  REQUIRES( isHandleRangeValid( iCryptHandle ) );
47  REQUIRES( errorInfo != NULL );
48 
49  /* Clear return value */
50  *isCertUpdate = FALSE;
51 
52  /* Check what we can update (if anything) */
53  unneededKey = privkeyPresent & pkcs15keyPresent;
54  unneededCert = certPresent & pkcs15certPresent;
55  if( ( ( unneededCert && !privkeyPresent ) || \
56  ( unneededKey && unneededCert ) ) && \
57  pkcs15infoPtr->validTo > MIN_TIME_VALUE )
58  {
59  time_t validTo;
60 
61  /* The certificate would be a duplicate, see if it's more recent
62  than the existing one. We only perform this check if there's a
63  validTo time stored for the certificate since without this
64  restriction any certificate without a stored time could be
65  overwritten */
66  setMessageData( &msgData, &validTo, sizeof( time_t ) );
67  status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
68  &msgData, CRYPT_CERTINFO_VALIDTO );
69  if( cryptStatusOK( status ) && validTo > pkcs15infoPtr->validTo )
70  {
71  time_t validFrom;
72 
73  /* It's a newer certificate, don't treat it as a duplicate.
74  This check is effectively impossible to perform automatically
75  since there are an infinite number of variations that have to
76  be taken into account, for example a certificate for the same
77  key issued by a different CA, same CA but it's changed the
78  bits it sets in the keyUsage (digitalSignature vs.
79  nonRepudiation), slightly different issuer DN (Thawte
80  certificates with a date encoded in the DN), and so on and so
81  on. Because this really requires manual processing by a
82  human we don't even try and sort it all out but just allow a
83  certificate for a given key (checked by the ID match) to be
84  replaced by a newer certificate for the same key. This is
85  restrictive enough to prevent most obviously-wrong
86  replacements while being permissive enough to allow most
87  probably-OK replacements */
88  unneededCert = FALSE;
89  *isCertUpdate = TRUE;
90 
91  /* There's one special-case situation in which odd things can
92  happen when updating certificates and that's when adding a
93  future-dated certificate, which would result in the
94  certificate being replaced with one that can't be used yet.
95  There's no clean way to handle this because in order to know
96  what to do we'd have to be able to guess the intent of the
97  user, however for anything but signature certificates it's
98  likely that the hit-and-miss certificate checking performed
99  by most software won't even notice a future-dated
100  certificate, and for signature certificates the semantics of
101  signing data now using a certificate that isn't valid yet are
102  somewhat uncertain. Since in most cases no-one will even
103  notice the problem, we throw an exception in the debug build
104  but don't do anything in release builds. This is probably
105  less annoying to users than having the code reject an
106  otherwise-valid future-dated certificate. If anyone ever
107  complains about this then we can ask the users at that time
108  what sort of behaviour they're prefer */
109  setMessageData( &msgData, &validFrom, sizeof( time_t ) );
110  status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
111  &msgData, CRYPT_CERTINFO_VALIDFROM );
112  if( cryptStatusOK( status ) && \
113  validFrom > getApproxTime() + 86400L )
114  {
115  assert( !"Attempt to replace certificate with future-dated certificate" );
116  }
117  }
118  }
119 
120  /* Make sure that we can update at least one of the objects in the PKCS
121  #15 personality */
122  if( ( unneededKey && !certPresent ) || /* Key only, duplicate */
123  ( unneededCert && !privkeyPresent ) || /* Certificate only, duplicate */
124  ( unneededKey && unneededCert ) ) /* Key+certificate, duplicate */
125  {
126  /* If it's anything other than a certificate chain, we can't add
127  anything */
128  if( !isCertChain )
129  {
131  ( CRYPT_ERROR_DUPLICATE, errorInfo,
132  "No new data to add" ) );
133  }
134 
135  /* Tell the caller that it's an opportunistic certificate-chain
136  update */
137  return( OK_SPECIAL );
138  }
139 
140  return( CRYPT_OK );
141  }
142 
143 /****************************************************************************
144 * *
145 * Add a Key *
146 * *
147 ****************************************************************************/
148 
149 /* Add an item to the PKCS #15 keyset */
150 
152 static int setItemFunction( INOUT KEYSET_INFO *keysetInfoPtr,
154  IN_ENUM( KEYMGMT_ITEM ) \
155  const KEYMGMT_ITEM_TYPE itemType,
156  IN_BUFFER_OPT( passwordLength ) const char *password,
158  IN_FLAGS( KEYMGMT ) const int flags )
159  {
161  PKCS15_INFO *pkcs15info = keysetInfoPtr->keyData, *pkcs15infoPtr;
163  BYTE iD[ CRYPT_MAX_HASHSIZE + 8 ];
164  const BOOLEAN isStorageObject = \
165  ( keysetInfoPtr->keysetFile->iHardwareDevice != CRYPT_UNUSED ) ? \
166  TRUE : FALSE;
167  BOOLEAN certPresent = FALSE, privkeyPresent = FALSE;
168  BOOLEAN pkcs15certPresent = FALSE, pkcs15keyPresent = FALSE;
169  BOOLEAN isCertChain = FALSE, isCertUpdate = FALSE;
170  const int noPkcs15objects = keysetInfoPtr->keyDataNoObjects;
171  int pkcs15index = CRYPT_ERROR, iDsize, value, status;
172 
173  assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
174  assert( isWritePtr( pkcs15info, \
175  sizeof( PKCS15_INFO ) * noPkcs15objects ) );
176 
177  REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
178  keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS15 );
179  REQUIRES( isHandleRangeValid( cryptHandle ) );
180  REQUIRES( itemType == KEYMGMT_ITEM_PUBLICKEY || \
181  itemType == KEYMGMT_ITEM_PRIVATEKEY || \
182  itemType == KEYMGMT_ITEM_SECRETKEY || \
183  itemType == KEYMGMT_ITEM_KEYMETADATA );
184  REQUIRES( ( password == NULL && passwordLength == 0 ) || \
185  ( password != NULL && \
186  passwordLength >= MIN_NAME_LENGTH && \
187  passwordLength < MAX_ATTRIBUTE_SIZE ) );
188  REQUIRES( ( ( itemType == KEYMGMT_ITEM_PUBLICKEY || \
189  itemType == KEYMGMT_ITEM_KEYMETADATA ) && \
190  password == NULL && passwordLength == 0 ) || \
191  ( ( itemType == KEYMGMT_ITEM_PRIVATEKEY || \
192  itemType == KEYMGMT_ITEM_SECRETKEY ) && \
193  password != NULL && passwordLength != 0 ) );
194  REQUIRES( ( isStorageObject && \
195  ( itemType == KEYMGMT_ITEM_PUBLICKEY || \
196  itemType == KEYMGMT_ITEM_KEYMETADATA ) ) || \
197  ( !isStorageObject && \
198  itemType != KEYMGMT_ITEM_KEYMETADATA ) );
199  REQUIRES( flags == KEYMGMT_FLAG_NONE );
200 
201  /* If we're being sent a secret key, add it to the PKCS #15 keyset and
202  exit */
203  if( itemType == KEYMGMT_ITEM_SECRETKEY )
204  return( addSecretKey( pkcs15info, noPkcs15objects, cryptHandle ) );
205 
206  /* Check the object, extract ID information from it, and determine
207  whether it's a standalone certificate (which produces a PKCS #15
208  certificate object) or a private-key context (which produces a PKCS
209  #15 private key object and either a PKCS #15 public-key object (if
210  there's no certificate present) or a certificate object (if there's
211  a certificate present)). If it's a dummy context being used to
212  store key metadata then it won't necessarily be usable for encryption
213  operations so we skip the initial check in this case, the kernel will
214  already have performed the basic type check.
215 
216  Note that we don't allow the addition of standalone public keys
217  (without corresponding private keys) since these keysets are private-
218  key keysets and not general-purpose public key exchange mechanisms.
219  Without this safeguard some users would use them as a general public-
220  key store in place of database keysets or (more rarely) as a type of
221  unsigned certificate for exchanging public keys.
222 
223  In addition allowing the storage of standalone public keys is rather
224  problematic since they need to have a label attached in order to be
225  identified so performing a public-key add with a private-key context
226  would work but performing one with a public-key context would fail.
227  A certificate update on this public-key-only item would result in the
228  presence a private-key-labelled certificate, which is even more
229  strange for users to comprehend. To keep things sensible we
230  therefore disallow the addition of standalone public keys */
231  if( itemType != KEYMGMT_ITEM_KEYMETADATA )
232  {
233  status = krnlSendMessage( cryptHandle, IMESSAGE_CHECK, NULL,
235  if( cryptStatusError( status ) )
236  return( cryptArgError( status ) ? CRYPT_ARGERROR_NUM1 : status );
237  if( cryptStatusOK( \
238  krnlSendMessage( cryptHandle, IMESSAGE_CHECK, NULL,
240  privkeyPresent = TRUE;
241  }
242  else
243  {
244  /* Private-key metadata implicitly has a private key present even
245  if it's not explicitly present in the dummy context */
246  privkeyPresent = TRUE;
247  }
248  setMessageData( &msgData, iD, CRYPT_MAX_HASHSIZE );
249  status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
250  &msgData, CRYPT_IATTRIBUTE_KEYID );
251  if( cryptStatusError( status ) )
252  return( status );
253  iDsize = msgData.length;
254 
255  /* If the object being added isn't a generic public key/certificate and
256  is bound to crypto hardware, make sure that this keyset is PKCS #15
257  object store */
258  if( itemType != KEYMGMT_ITEM_PUBLICKEY )
259  {
260  setMessageData( &msgData, NULL, 0 );
261  status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
262  &msgData,
263  CRYPT_IATTRIBUTE_DEVICESTORAGEID );
264  if( cryptStatusOK( status ) )
265  {
266  /* A hardware-bound object can't be added to a general-purpose
267  keyset because there's no way to access the key components
268  that are required to be stored */
269  if( !isStorageObject )
270  return( CRYPT_ERROR_PERMISSION );
271  }
272  else
273  {
274  if( isStorageObject )
275  return( CRYPT_ERROR_PERMISSION );
276  }
277  }
278 
279  /* If we're adding a private key make sure that there's a context and a
280  password present. Conversely if we're adding a public key make sure
281  that there's no password present. The password-check has already
282  been performed by the kernel but we perform a second check here just
283  to be safe. The private-key check can't be performed by the kernel
284  since it doesn't know the difference between public- and private-key
285  contexts */
286  switch( itemType )
287  {
290  if( password != NULL )
291  return( CRYPT_ARGERROR_STR1 );
292  break;
293 
295  if( !privkeyPresent )
296  {
299  "Item being added doesn't contain a private "
300  "key" ) );
301  }
302  if( password == NULL )
303  return( CRYPT_ARGERROR_STR1 );
304  break;
305 
306  default:
307  retIntError();
308  }
309 
310  /* If there's a certificate present make sure that it's something that
311  can be stored. We don't treat the wrong type as an error since we
312  can still store the public/private key components even if we don't
313  store the certificate */
314  if( cryptStatusOK( \
315  krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE, &value,
316  CRYPT_CERTINFO_CERTTYPE ) ) && \
317  ( value == CRYPT_CERTTYPE_CERTIFICATE || \
318  value == CRYPT_CERTTYPE_CERTCHAIN ) )
319  {
320  /* If it's a certificate chain, remember this for later since we may
321  need to store multiple certificates */
322  if( value == CRYPT_CERTTYPE_CERTCHAIN )
323  isCertChain = TRUE;
324 
325  /* If the certificate isn't signed then we can't store it in this
326  state */
327  status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE,
328  &value, CRYPT_CERTINFO_IMMUTABLE );
329  if( cryptStatusError( status ) || !value )
330  {
333  "Certificate being added is incomplete (unsigned)" ) );
334  }
335 
336  /* Get a reference to the certificate that's associated with the
337  context. We have to do this in order to lock it so that we can
338  store it since the lock operation is only valid for certificates
339  and not contexts */
340  status = krnlSendMessage( cryptHandle, IMESSAGE_GETDEPENDENT,
341  &iCryptCert, OBJECT_TYPE_CERTIFICATE );
342  if( cryptStatusError( status ) )
343  return( status );
344  certPresent = TRUE;
345  }
346 
347  /* Find out where we can add data and what needs to be added. The
348  strategy for adding items is:
349 
350  Existing
351  New | None | Priv+Pub | Priv+Cert | Cert |
352  ------------+-----------+-----------+-----------+-----------+
353  Priv + Pub | Add | ---- | ---- | Add |
354  | | | | |
355  Priv + Cert | Add | Repl.pubk | Add cert | Add cert |
356  | | with cert | if newer | if newer |
357  Cert | If trusted| Add | Add cert | Add cert |
358  | | | if newer | if newer |
359  ------------+-----------+-----------+-----------+-----------+
360 
361  We don't check for the addition of a trusted certificate at this
362  point since it could be buried in the middle of a certificate chain
363  so we leave the checking to addCertChain() */
364  pkcs15infoPtr = findEntry( pkcs15info, noPkcs15objects, CRYPT_KEYIDEX_ID,
365  iD, iDsize, KEYMGMT_FLAG_NONE );
366  if( pkcs15infoPtr != NULL )
367  {
368  /* Determine what actually needs to be added */
369  if( pkcs15infoPtr->privKeyData != NULL )
370  pkcs15keyPresent = TRUE;
371  if( pkcs15infoPtr->certData != NULL )
372  pkcs15certPresent = TRUE;
373 
374  /* See what we can add */
375  status = checkAddInfo( pkcs15infoPtr, cryptHandle, isCertChain,
376  privkeyPresent, certPresent,
377  pkcs15keyPresent, pkcs15certPresent,
378  &isCertUpdate, KEYSET_ERRINFO );
379  if( cryptStatusError( status ) )
380  {
381  /* If it's not an OK_SPECIAL status telling us that we can still
382  try for an opportunistic certificate chain add, exit */
383  if( status != OK_SPECIAL )
384  return( status );
385 
386  /* In theory we can't add anything, however since we've been
387  given a certificate chain there may be new certificates
388  present that we can try and add opportunistically */
389  status = krnlSendMessage( cryptHandle, IMESSAGE_SETATTRIBUTE,
391  CRYPT_IATTRIBUTE_LOCKED );
392  if( cryptStatusError( status ) )
393  return( status );
394  status = pkcs15AddCertChain( pkcs15infoPtr, noPkcs15objects,
395  cryptHandle, KEYSET_ERRINFO );
396  ( void ) krnlSendMessage( cryptHandle, IMESSAGE_SETATTRIBUTE,
398  CRYPT_IATTRIBUTE_LOCKED );
399  return( status );
400  }
401  }
402  else
403  {
404  /* This key/certificate isn't already present, make sure that the
405  label of what we're adding doesn't duplicate the label of an
406  existing object */
407  if( privkeyPresent )
408  {
409  char label[ CRYPT_MAX_TEXTSIZE + 8 ];
410 
411  setMessageData( &msgData, label, CRYPT_MAX_TEXTSIZE );
412  status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
413  &msgData, CRYPT_CTXINFO_LABEL );
414  if( cryptStatusError( status ) )
415  return( status );
416  if( findEntry( pkcs15info, noPkcs15objects, CRYPT_KEYID_NAME,
417  msgData.data, msgData.length,
418  KEYMGMT_FLAG_NONE ) != NULL )
419  {
422  "Item with this label is already present" ) );
423  }
424  }
425 
426  /* Find out where we can add the new key data */
427  pkcs15infoPtr = findFreeEntry( pkcs15info, noPkcs15objects,
428  &pkcs15index );
429  if( pkcs15infoPtr == NULL )
430  {
433  "No more room in keyset to add this item" ) );
434  }
435  }
436 
437  /* We're ready to go, lock the object for our exclusive use */
438  if( certPresent )
439  {
440  status = krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE,
442  CRYPT_IATTRIBUTE_LOCKED );
443  if( cryptStatusError( status ) )
444  return( status );
445  }
446 
447  /* Add the key data. This will add the public/private key and any
448  certificate data associated with the key as required */
449  status = pkcs15AddKey( pkcs15infoPtr, cryptHandle, password,
450  passwordLength, keysetInfoPtr->ownerHandle,
451  privkeyPresent, certPresent,
452  ( isCertUpdate || !pkcs15certPresent ) ? \
453  TRUE : FALSE,
454  pkcs15keyPresent, isStorageObject,
455  KEYSET_ERRINFO );
456  if( cryptStatusError( status ) )
457  {
458  if( certPresent )
459  {
460  ( void ) krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE,
462  CRYPT_IATTRIBUTE_LOCKED );
463  }
464  return( status );
465  }
466 
467  /* The update was successful, update the type and index information if
468  this was a newly-created entry */
469  if( pkcs15index != CRYPT_ERROR )
470  {
471  pkcs15infoPtr->type = PKCS15_SUBTYPE_NORMAL;
472  pkcs15infoPtr->index = pkcs15index;
473  }
474 
475  /* If we've been given a certificate chain, try and opportunistically
476  add any further certificates that may be present in it. Error
477  handling once we get this far gets a bit tricky, we can still get an
478  error at this point if the certificate chain update fails even if the
479  main certificate add succeeded, however it's uncertain whether we
480  should still report an error when the main intended update (of the
481  private key and public key or certificate) succeeded. Since the
482  primary items to be added are the keys and a corresponding
483  certificate (as handled in addKey()) we don't report an error if
484  adding one of the coincidental certificates fails, since the primary
485  items were added successfully */
486  if( isCertChain )
487  {
488  ( void ) pkcs15AddCertChain( pkcs15infoPtr, noPkcs15objects,
489  cryptHandle, KEYSET_ERRINFO );
490  }
491 
492  /* Clean up */
493  if( certPresent )
494  {
495  ( void ) krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE,
497  CRYPT_IATTRIBUTE_LOCKED );
498  }
499  return( status );
500  }
501 
502 /* Add special data to the PKCS #15 keyset */
503 
504 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
505 static int setSpecialItemFunction( INOUT KEYSET_INFO *keysetInfoPtr,
506  IN_ATTRIBUTE \
508  IN_BUFFER( dataLength ) const void *data,
509  IN_LENGTH_SHORT const int dataLength )
510  {
511  PKCS15_INFO *pkcs15info = keysetInfoPtr->keyData;
512  const int noPkcs15objects = keysetInfoPtr->keyDataNoObjects;
513 
514  assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
515  assert( isWritePtr( pkcs15info, \
516  sizeof( PKCS15_INFO ) * noPkcs15objects ) );
517  assert( isReadPtr( data, dataLength ) );
518 
519  REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
520  keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS15 );
521  REQUIRES( dataType == CRYPT_IATTRIBUTE_CONFIGDATA || \
522  dataType == CRYPT_IATTRIBUTE_USERINDEX || \
523  dataType == CRYPT_IATTRIBUTE_USERID || \
524  dataType == CRYPT_IATTRIBUTE_USERINFO || \
525  dataType == CRYPT_IATTRIBUTE_HWSTORAGE );
526  REQUIRES( dataLength > 0 && dataLength < MAX_INTLENGTH_SHORT );
527 
528  /* Some hardware devices use PKCS #15 as their storage format for
529  structured data, in which case this is a notification that some rules
530  about what can be added to a PKCS #15 keyset can be relaxed */
531  if( dataType == CRYPT_IATTRIBUTE_HWSTORAGE )
532  {
533  keysetInfoPtr->keysetFile->iHardwareDevice = \
534  *( ( CRYPT_HANDLE * ) data );
535  return( CRYPT_OK );
536  }
537 
538  return( addConfigData( pkcs15info, noPkcs15objects, dataType,
539  data, dataLength ) );
540  }
541 
542 /****************************************************************************
543 * *
544 * Delete a Key *
545 * *
546 ****************************************************************************/
547 
548 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
549 static int deleteItemFunction( INOUT KEYSET_INFO *keysetInfoPtr,
550  IN_ENUM( KEYMGMT_ITEM ) \
551  const KEYMGMT_ITEM_TYPE itemType,
553  IN_BUFFER( keyIDlength ) const void *keyID,
554  IN_LENGTH_KEYID const int keyIDlength )
555  {
557 
558  assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
559  assert( isReadPtr( keyID, keyIDlength ) );
560 
561  REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
562  keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS15 );
563  REQUIRES( itemType > KEYMGMT_ITEM_NONE && \
564  itemType < KEYMGMT_ITEM_LAST );
565  REQUIRES( keyIDtype == CRYPT_KEYID_NAME || \
566  keyIDtype == CRYPT_KEYID_URI || \
567  keyIDtype == CRYPT_IKEYID_KEYID || \
568  keyIDtype == CRYPT_IKEYID_ISSUERID );
569  REQUIRES( keyIDlength >= MIN_NAME_LENGTH && \
570  keyIDlength < MAX_ATTRIBUTE_SIZE );
571 
572  /* Locate the appropriate object in the PKCS #15 collection */
573  pkcs15infoPtr = findEntry( keysetInfoPtr->keyData,
574  keysetInfoPtr->keyDataNoObjects, keyIDtype,
575  keyID, keyIDlength, KEYMGMT_FLAG_NONE );
576  if( pkcs15infoPtr == NULL )
577  {
580  "No information present for this ID" ) );
581  }
582 
583  /* Clear this entry */
584  pkcs15freeEntry( pkcs15infoPtr );
585 
586  return( CRYPT_OK );
587  }
588 
589 /****************************************************************************
590 * *
591 * Keyset Access Routines *
592 * *
593 ****************************************************************************/
594 
596 int initPKCS15set( KEYSET_INFO *keysetInfoPtr )
597  {
598  assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
599 
600  REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
601  keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS15 );
602 
603  /* Set the access method pointers */
604  keysetInfoPtr->setItemFunction = setItemFunction;
605  keysetInfoPtr->setSpecialItemFunction = setSpecialItemFunction;
606  keysetInfoPtr->deleteItemFunction = deleteItemFunction;
607 
608  return( CRYPT_OK );
609  }
610 #endif /* USE_PKCS15 */