cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
cryptkey.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib Keyset Routines *
4 * Copyright Peter Gutmann 1995-2007 *
5 * *
6 ****************************************************************************/
7 
8 #include <stdio.h>
9 #include <stdarg.h>
10 #include "crypt.h"
11 #ifdef INC_ALL
12  #include "asn1.h"
13  #include "asn1_ext.h"
14  #include "pgp_rw.h"
15  #include "keyset.h"
16 #else
17  #include "enc_dec/asn1.h"
18  #include "enc_dec/asn1_ext.h"
19  #include "enc_dec/pgp_rw.h"
20  #include "keyset/keyset.h"
21 #endif /* Compiler-specific includes */
22 
23 #ifdef USE_KEYSETS
24 
25 /****************************************************************************
26 * *
27 * Utility Functions *
28 * *
29 ****************************************************************************/
30 
31 /* Clear the extended error information that may be present from a previous
32  operation prior to beginning a new operation */
33 
34 STDC_NONNULL_ARG( ( 1 ) ) \
35 static void resetErrorInfo( INOUT KEYSET_INFO *keysetInfoPtr )
36  {
37  ERROR_INFO *errorInfo = &keysetInfoPtr->errorInfo;
38 
39  assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
40 
41  memset( errorInfo, 0, sizeof( ERROR_INFO ) );
42  }
43 
44 /* Prepare to update a keyset, performing various access checks and pre-
45  processing of information */
46 
47 typedef struct {
48  CRYPT_KEYID_TYPE keyIDtype; /* KeyID type */
50  const void *keyID; /* KeyID value */
51  int keyIDlength;
52  } KEYID_INFO;
53 
55 static int initKeysetUpdate( INOUT KEYSET_INFO *keysetInfoPtr,
56  INOUT_OPT KEYID_INFO *keyIDinfo,
57  OUT_BUFFER_OPT_FIXED( keyIdMaxLength ) \
58  void *keyIDbuffer,
59  IN_LENGTH_SHORT_Z const int keyIdMaxLength,
60  const BOOLEAN isRead )
61  {
62  assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
63  assert( ( keyIDinfo == NULL && \
64  keyIDbuffer == NULL && keyIdMaxLength == 0 ) || \
65  ( isWritePtr( keyIDinfo, sizeof( KEYID_INFO ) ) && \
66  isReadPtr( keyIDbuffer, keyIdMaxLength ) ) );
67 
68  REQUIRES( ( keyIDinfo == NULL && \
69  keyIDbuffer == NULL && keyIdMaxLength == 0 ) || \
70  ( keyIDinfo != NULL && \
71  keyIDbuffer != NULL && keyIdMaxLength == KEYID_SIZE ) );
72 
73  /* If we're in the middle of a query we can't do anything else */
74  if( keysetInfoPtr->isBusyFunction != NULL && \
75  keysetInfoPtr->isBusyFunction( keysetInfoPtr ) )
76  return( CRYPT_ERROR_INCOMPLETE );
77 
78  /* If we've been passed a full issuerAndSerialNumber as a key ID and the
79  keyset needs an issuerID, convert it */
80  if( keyIDinfo != NULL && \
81  keyIDinfo->keyIDtype == CRYPT_IKEYID_ISSUERANDSERIALNUMBER && \
82  ( keysetInfoPtr->type == KEYSET_DBMS || \
83  ( keysetInfoPtr->type == KEYSET_FILE && \
84  keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS15 ) ) )
85  {
86  HASHFUNCTION_ATOMIC hashFunctionAtomic;
87  int hashSize;
88 
89  /* Get the hash algorithm information */
90  getHashAtomicParameters( CRYPT_ALGO_SHA1, 0, &hashFunctionAtomic,
91  &hashSize );
92 
93  /* Hash the full iAndS to get an issuerID and use that for the keyID */
94  hashFunctionAtomic( keyIDbuffer, keyIdMaxLength, keyIDinfo->keyID,
95  keyIDinfo->keyIDlength );
96  keyIDinfo->keyIDtype = CRYPT_IKEYID_ISSUERID;
97  keyIDinfo->keyID = keyIDbuffer;
98  keyIDinfo->keyIDlength = hashSize;
99  }
100 
101  /* If this is a read access there's nothing further to do */
102  if( isRead )
103  return( CRYPT_OK );
104 
105  /* This is a write update, make sure that we can write to the keyset.
106  This covers all possibilities, both keyset types for which writing
107  isn't supported and individual keysets that we can't write to
108  because of things like file permissions, so once we pass this check
109  we know that we can write to the keyset */
110  if( keysetInfoPtr->options == CRYPT_KEYOPT_READONLY )
111  return( CRYPT_ERROR_PERMISSION );
112 
113  return( CRYPT_OK );
114  }
115 
116 /****************************************************************************
117 * *
118 * Flat-file Keyset Functions *
119 * *
120 ****************************************************************************/
121 
122 /* OID information used to read the header of a PKCS #15 file. Since the
123  PKCS #15 content can be further wrapped in CMS AuthData we have to check
124  for both types of content */
125 
126 static const CMS_CONTENT_INFO FAR_BSS oidInfoPkcs15Data = { 0, 0 };
127 
128 static const OID_INFO FAR_BSS keyFileOIDinfo[] = {
129  { OID_PKCS15_CONTENTTYPE, TRUE, &oidInfoPkcs15Data },
130  { OID_CMS_AUTHDATA, FALSE, &oidInfoPkcs15Data },
131  { NULL, 0 }, { NULL, 0 }
132  };
133 
134 /* Identify a flat-file keyset type */
135 
136 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
137 static int getKeysetType( INOUT STREAM *stream,
139  {
140  long length;
141  int value, status;
142 
143  assert( isWritePtr( stream, sizeof( STREAM ) ) );
144  assert( isWritePtr( subType, sizeof( KEYSET_SUBTYPE ) ) );
145 
146  /* Clear return value */
147  *subType = KEYSET_SUBTYPE_NONE;
148 
149  /* Try and guess the basic type */
150  status = value = sPeek( stream );
151  if( cryptStatusError( status ) )
152  return( status );
153  if( value == BER_SEQUENCE )
154  {
155  /* Read the length of the object, which should be between 64 and 64K
156  bytes in size. We have to allow for very tiny files to handle
157  PKCS #15 files that contain only configuration data, and rather
158  large ones to handle the existence of large numbers of trusted
159  certificates, with a maximum of 32 objects * ~2K per object we
160  can get close to 64K in size. The length may also be zero if the
161  indefinite encoding form is used. Although PKCS #15 specifies
162  the use of DER, it doesn't hurt to allow this at least for the
163  outer wrapper, if Microsoft ever move to PKCS #15 they're bound
164  to get it wrong */
165  status = readLongSequence( stream, &length );
166  if( cryptStatusError( status ) )
167  return( status );
168  if( length != CRYPT_UNUSED && ( length < 64 || length > 65535L ) )
169  return( CRYPT_ERROR_BADDATA );
170 
171  /* Check for a PKCS #12/#15 file */
172  if( peekTag( stream ) == BER_INTEGER )
173  {
174  long version;
175 
176  /* Check for a PKCS #12 version number */
177  status = readShortInteger( stream, &version );
178  if( cryptStatusError( status ) )
179  return( status );
180  if( version != 3 )
181  return( CRYPT_ERROR_BADDATA );
182  *subType = KEYSET_SUBTYPE_PKCS12;
183 
184  return( CRYPT_OK );
185  }
186 
187  /* Check for a PKCS #15 file type, either direct PKCS #15 content
188  or PKCS #15 wrapped in CMS AuthData */
189  status = readOID( stream, keyFileOIDinfo,
190  FAILSAFE_ARRAYSIZE( keyFileOIDinfo, OID_INFO ),
191  &value );
192  if( cryptStatusError( status ) )
193  return( status );
194  *subType = KEYSET_SUBTYPE_PKCS15;
195 
196  return( CRYPT_OK );
197  }
198 #ifdef USE_PGP
199  value = pgpGetPacketType( value );
200  if( value == PGP_PACKET_PUBKEY || value == PGP_PACKET_SECKEY )
201  {
203 
204  /* Determine the file type based on the initial CTB */
205  type = ( value == PGP_PACKET_PUBKEY ) ? \
207 
208  /* Perform a sanity check to make sure that the rest looks like a
209  PGP keyring */
210  status = pgpReadPacketHeader( stream, &value, &length, 64 );
211  if( cryptStatusError( status ) )
212  return( status );
213  if( type == KEYSET_SUBTYPE_PGP_PUBLIC )
214  {
215  if( length < 64 || length > 1024 )
216  return( CRYPT_ERROR_BADDATA );
217  }
218  else
219  {
220  if( length < 200 || length > 4096 )
221  return( CRYPT_ERROR_BADDATA );
222  }
223  status = value = sgetc( stream );
224  if( cryptStatusError( status ) )
225  return( status );
226  if( value != PGP_VERSION_2 && value != PGP_VERSION_3 && \
227  value != PGP_VERSION_OPENPGP )
228  return( CRYPT_ERROR_BADDATA );
229  *subType = type;
230 
231  return( CRYPT_OK );
232  }
233 #endif /* USE_PGP */
234 
235  /* "It doesn't look like anything from here" */
236  return( CRYPT_ERROR_BADDATA );
237  }
238 
239 /* Open a flat-file keyset */
240 
241 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 5, 6 ) ) \
242 static int openKeysetStream( INOUT STREAM *stream,
243  IN_BUFFER( nameLength ) const char *name,
245  const int nameLength,
246  IN_ENUM_OPT( CRYPT_KEYOPT ) \
248  OUT_BOOL BOOLEAN *isReadOnly,
250  KEYSET_SUBTYPE *keysetSubType )
251  {
253  char nameBuffer[ MAX_ATTRIBUTE_SIZE + 1 + 8 ];
254  const int suffixPos = nameLength - 4;
255  int openMode, status;
256 
257  assert( isWritePtr( stream, sizeof( STREAM ) ) );
258  assert( isReadPtr( name, nameLength ) );
259  assert( isWritePtr( isReadOnly, sizeof( BOOLEAN ) ) );
260  assert( isWritePtr( keysetSubType, sizeof( KEYSET_SUBTYPE ) ) );
261 
262  REQUIRES( options >= CRYPT_KEYOPT_NONE && options < CRYPT_KEYOPT_LAST );
263  REQUIRES( nameLength >= MIN_NAME_LENGTH && \
264  nameLength < MAX_ATTRIBUTE_SIZE );
265 
266  /* Clear return values */
267  *isReadOnly = FALSE;
268  *keysetSubType = KEYSET_SUBTYPE_NONE;
269 
270  /* Convert the keyset name into a null-terminated string */
271  memcpy( nameBuffer, name, nameLength );
272  nameBuffer[ nameLength ] = '\0';
273 
274  /* Get the expected subtype based on the keyset name (the default is
275  PKCS #15 if no contraindication is found in the file suffix) */
276  if( suffixPos > 0 && nameBuffer[ suffixPos ] == '.' )
277  {
278  if( !strCompare( nameBuffer + suffixPos + 1, "pgp", 3 ) || \
279  !strCompare( nameBuffer + suffixPos + 1, "gpg", 3 ) || \
280  !strCompare( nameBuffer + suffixPos + 1, "pkr", 3 ) )
281  subType = KEYSET_SUBTYPE_PGP_PUBLIC;
282  if( !strCompare( nameBuffer + suffixPos + 1, "skr", 3 ) )
283  subType = KEYSET_SUBTYPE_PGP_PRIVATE;
284  if( !strCompare( nameBuffer + suffixPos + 1, "pfx", 3 ) || \
285  !strCompare( nameBuffer + suffixPos + 1, "p12", 3 ) )
286  subType = KEYSET_SUBTYPE_PKCS12;
287  }
288 
289  /* If the file is read-only, put the keyset into read-only mode */
290  if( fileReadonly( nameBuffer ) )
291  {
292  /* If we want to create a new file we can't do it if we don't have
293  write permission */
294  if( options == CRYPT_KEYOPT_CREATE )
295  return( CRYPT_ERROR_PERMISSION );
296 
297  /* Open the file in read-only mode */
298  *isReadOnly = TRUE;
299  openMode = FILE_FLAG_READ;
300  }
301  else
302  {
303  /* If we're creating the file, open it in write-only mode. Since
304  we'll (presumably) be storing private keys in it we mark it as
305  both private (owner-access-only ACL) and sensitive (store in
306  secure storage if possible) */
307  if( options == CRYPT_KEYOPT_CREATE )
309  FILE_FLAG_PRIVATE | FILE_FLAG_SENSITIVE;
310  else
311  {
312  /* Open it for read or read/write depending on whether the
313  readonly flag is set */
314  openMode = ( options == CRYPT_KEYOPT_READONLY ) ? \
316  }
317  }
318  if( options == CRYPT_IKEYOPT_EXCLUSIVEACCESS )
319  openMode |= FILE_FLAG_EXCLUSIVE_ACCESS;
320 
321  /* Pre-open the file containing the keyset. This initially opens it in
322  read-only mode for auto-detection of the file type so we can check for
323  various problems */
324  status = sFileOpen( stream, nameBuffer, FILE_FLAG_READ );
325  if( cryptStatusError( status ) )
326  {
327  /* The file can't be opened, if the create-new-file flag isn't set
328  return an error. If it is set, make sure that we're trying to
329  create a writeable keyset type */
330  if( options != CRYPT_KEYOPT_CREATE )
331  return( status );
332  if( !isWriteableFileKeyset( subType ) )
333  return( CRYPT_ERROR_NOTAVAIL );
334 
335  /* Try and create a new file */
336  status = sFileOpen( stream, nameBuffer, openMode );
337  if( cryptStatusError( status ) )
338  {
339  /* The file isn't open at this point so we have to exit
340  explicitly rather than falling through to the error handler
341  below */
342  return( status );
343  }
344  }
345  else
346  {
347  /* If we're opening an existing keyset, get its type and make sure
348  that it's valid */
349  if( options != CRYPT_KEYOPT_CREATE )
350  {
351  BYTE buffer[ 512 + 8 ];
352 
353  sioctlSetString( stream, STREAM_IOCTL_IOBUFFER, buffer, 512 );
354  status = getKeysetType( stream, &subType );
355  if( cryptStatusError( status ) )
356  {
357  /* "It doesn't look like anything from here" */
358  sFileClose( stream );
359  return( CRYPT_ERROR_BADDATA );
360  }
361  sseek( stream, 0 );
362  sioctlSet( stream, STREAM_IOCTL_IOBUFFER, 0 );
363  }
364 
365  /* If it's a cryptlib keyset we can open it in any mode */
366  if( isWriteableFileKeyset( subType ) )
367  {
368  /* If we're opening it something other than read-only mode,
369  reopen it in that mode. Note that in theory this could make
370  us subject to a TOCTTOU attack but the only reason that we're
371  opening the file initially is to determine its type, so if an
372  attacker slips in a different file on the re-open it'll
373  either be a no-op if it's the same file type or we'll get a
374  CRYPT_ERROR_BADDATA if it's the same file type */
375  if( openMode != FILE_FLAG_READ )
376  {
377  sFileClose( stream );
378  status = sFileOpen( stream, nameBuffer, openMode );
379  if( cryptStatusError( status ) )
380  return( status ); /* Exit with file closed */
381  }
382  }
383  else
384  {
385  /* If it's a non-cryptlib keyset we can't open it for anything
386  other than read-only access. We return a not-available error
387  rather than a permission error since this isn't a problem with
388  access permissions for the file but the fact that the code to
389  write the key doesn't exist */
390  if( options != CRYPT_KEYOPT_READONLY )
391  status = CRYPT_ERROR_NOTAVAIL;
392  }
393  }
394  if( cryptStatusError( status ) )
395  {
396  sFileClose( stream );
397  return( status );
398  }
399 
400  *keysetSubType = subType;
401  return( CRYPT_OK );
402  }
403 
404 /* Complete the open of a file keyset */
405 
406 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
407 static int completeKeysetFileOpen( INOUT KEYSET_INFO *keysetInfoPtr,
409  KEYSET_SUBTYPE subType,
410  INOUT STREAM *stream,
411  IN_BUFFER( nameLength ) const char *name,
413  const int nameLength )
414  {
415  FILE_INFO *fileInfo = keysetInfoPtr->keysetFile;
416  BYTE buffer[ STREAM_BUFSIZE + 8 ];
417  int status;
418 
419  assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
420  assert( isReadPtr( name, nameLength ) );
421  assert( isWritePtr( stream, sizeof( STREAM ) ) );
422 
423  REQUIRES( subType > KEYSET_SUBTYPE_NONE && \
424  subType < KEYSET_SUBTYPE_LAST );
425  REQUIRES( nameLength >= MIN_NAME_LENGTH && \
426  nameLength < MAX_ATTRIBUTE_SIZE );
427 
428  /* Remember the key file's name (as a null-terminated string for
429  filesystem access) and I/O stream */
430  if( nameLength > MAX_PATH_LENGTH - 1 )
431  return( CRYPT_ARGERROR_STR1 );
432  keysetInfoPtr->subType = subType;
433  memcpy( fileInfo->fileName, name, nameLength );
434  fileInfo->fileName[ nameLength ] = '\0';
435  memcpy( &fileInfo->stream, stream, sizeof( STREAM ) );
436 
437  /* Set various values to their default settings */
438  fileInfo->iHardwareDevice = CRYPT_UNUSED;
439 
440  /* Make sure that we don't accidentally reuse the standalone stream */
441  memset( stream, 0, sizeof( STREAM ) );
442 
443  /* Set up the access information for the file */
444  switch( keysetInfoPtr->subType )
445  {
447  status = setAccessMethodPKCS12( keysetInfoPtr );
448  break;
449 
451  status = setAccessMethodPKCS15( keysetInfoPtr );
452  break;
453 
455  status = setAccessMethodPGPPublic( keysetInfoPtr );
456  break;
457 
459  status = setAccessMethodPGPPrivate( keysetInfoPtr );
460  break;
461 
462  default:
463  retIntError();
464  }
465  if( cryptStatusError( status ) )
466  {
467  /* Normally if an access method is unavailable we'd return
468  CRYPT_ARGERROR_NUM1 to indicate that the overall CRYPT_KEYSET_xxx
469  type isn't supported, however in the case of CRYPT_KEYSET_FILE
470  we're dealing with subtypes rather than the CRYPT_KEYSET_FILE in
471  general. To deal with this, if the subtype is anything other than
472  PKCS #15 files then we report it as CRYPT_ERROR_NOTAVAIL to indicate
473  that while CRYPT_KEYSET_FILE as a whole may be supported, this
474  particular subtype isn't. For PKCS #15 files, the generic "file
475  keyset", we report it as a standard CRYPT_ARGERROR_NUM1 */
476  if( status == CRYPT_ARGERROR_NUM1 && \
477  subType != KEYSET_SUBTYPE_PKCS15 )
478  return( CRYPT_ERROR_NOTAVAIL );
479 
480  return( status );
481  }
482  ENSURES( keysetInfoPtr->initFunction != NULL && \
483  keysetInfoPtr->shutdownFunction != NULL && \
484  keysetInfoPtr->getItemFunction != NULL );
485  ENSURES( subType != SUBTYPE_KEYSET_FILE || \
486  ( keysetInfoPtr->getSpecialItemFunction != NULL && \
487  keysetInfoPtr->setItemFunction != NULL && \
488  keysetInfoPtr->setSpecialItemFunction != NULL && \
489  keysetInfoPtr->deleteItemFunction != NULL && \
490  keysetInfoPtr->getFirstItemFunction != NULL && \
491  keysetInfoPtr->getNextItemFunction != NULL ) );
492 
493  /* Read the keyset contents into memory */
494  sioctlSetString( &fileInfo->stream, STREAM_IOCTL_IOBUFFER, buffer,
495  STREAM_BUFSIZE );
496  status = keysetInfoPtr->initFunction( keysetInfoPtr, NULL, 0,
497  keysetInfoPtr->options );
498  sioctlSet( &fileInfo->stream, STREAM_IOCTL_IOBUFFER, 0 );
499  if( cryptStatusError( status ) )
500  return( status );
501 
502  /* If we've got the keyset open in read-only mode then we don't need to
503  touch it again since everything is cached in-memory, so we can close
504  the file stream */
505  if( ( keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS12 || \
506  keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS15 || \
507  keysetInfoPtr->subType == KEYSET_SUBTYPE_PGP_PRIVATE ) && \
508  ( keysetInfoPtr->options == CRYPT_KEYOPT_READONLY ) )
509  sFileClose( &fileInfo->stream );
510  else
511  {
512  /* Remember that the stream is still open for further access */
513  keysetInfoPtr->flags |= KEYSET_STREAM_OPEN;
514  }
515  keysetInfoPtr->flags |= KEYSET_OPEN;
516  if( keysetInfoPtr->options == CRYPT_KEYOPT_CREATE )
517  keysetInfoPtr->flags |= KEYSET_EMPTY;
518  return( CRYPT_OK );
519  }
520 
521 /****************************************************************************
522 * *
523 * Keyset Message Handler *
524 * *
525 ****************************************************************************/
526 
527 /* Handle a message sent to a keyset object */
528 
530 static int keysetMessageFunction( INOUT TYPECAST( KEYSET_INFO * ) \
531  void *objectInfoPtr,
533  void *messageDataPtr,
534  IN_INT_Z const int messageValue )
535  {
536  KEYSET_INFO *keysetInfoPtr = ( KEYSET_INFO * ) objectInfoPtr;
537  int status;
538 
539  assert( isWritePtr( objectInfoPtr, sizeof( KEYSET_INFO ) ) );
540 
541  REQUIRES( message > MESSAGE_NONE && message < MESSAGE_LAST );
542  REQUIRES( messageValue >= 0 && messageValue < MAX_INTLENGTH_SHORT );
543 
544  /* Process the destroy object message */
545  if( message == MESSAGE_DESTROY )
546  {
547  /* If the keyset is active, perform any required cleanup functions */
548  if( keysetInfoPtr->flags & KEYSET_OPEN )
549  {
550  /* Shut down the keyset */
551  status = keysetInfoPtr->shutdownFunction( keysetInfoPtr );
552  if( cryptStatusError( status ) )
553  {
554  assert( INTERNAL_ERROR );
555 
556  /* The shutdown failed for some reason. This can only
557  really ever happen for file keysets, in general there's
558  not much that we can do about this (see the long comment
559  about file-close failure conditions in io/file.c),
560  however in order to avoid leaving a potentially corrupted
561  file on disk we try and delete it if the shutdown fails.
562  (There are a pile of tradeoffs to be made here, for
563  example in theory we could rename the file to something
564  like .bak so that the user could try and recover
565  whatever's left in there, however it's unlikely that
566  they'll be able to do much with an unknown-condition
567  binary blob and in any case since we have no idea what
568  condition the file is in it's probably best to remove it
569  rather than to leave who knows what lying around on
570  disk) */
571  if( keysetInfoPtr->type == KEYSET_FILE && \
572  ( keysetInfoPtr->flags & KEYSET_STREAM_OPEN ) )
573  {
574  sFileClose( &keysetInfoPtr->keysetFile->stream );
575  fileErase( keysetInfoPtr->keysetFile->fileName );
576  }
577  }
578 
579  /* If it's a non-file keyset or a file keyset without an open
580  stream, we're done. Since we cache all information in a file
581  keyset and close the stream immediately afterwards if we've
582  opened it in read-only mode, we only close the underlying
583  stream for a file keyset if it's still active. Note the
584  distinction between the keyset being active and the stream
585  being active, for file keysets the keyset can be active
586  without being associated with an open stream */
587  if( keysetInfoPtr->type != KEYSET_FILE || \
588  !( keysetInfoPtr->flags & KEYSET_STREAM_OPEN ) )
589  return( CRYPT_OK );
590 
591  /* The keyset has an open file stream */
592  REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
593  ( keysetInfoPtr->flags & KEYSET_STREAM_OPEN ) );
594 
595  /* If the file keyset was updated in any way the update may have
596  changed the overall file size, in which case we need to clear
597  any leftover data from the previous version of the keyset
598  before we close the file */
599  if( keysetInfoPtr->flags & KEYSET_DIRTY )
600  fileClearToEOF( &keysetInfoPtr->keysetFile->stream );
601 
602  /* Close the keyset file (the keyset-specific handler sees only
603  an I/O stream and doesn't perform any file-level functions,
604  so we have to do this here) */
605  status = sFileClose( &keysetInfoPtr->keysetFile->stream );
606  if( cryptStatusError( status ) )
607  {
608  /* Try and remove the keyset if the file close failed and
609  would have left the file in an indeterminate state, see
610  the comment in io/file.c for more information */
611  fileErase( keysetInfoPtr->keysetFile->fileName );
612  }
613  else
614  {
615  /* If it's a newly-created empty keyset file or one in which
616  all of the keys have been deleted, remove it. This
617  situation can occur if there's some sort of error on
618  writing and no keys are ever written to the keyset */
619  if( keysetInfoPtr->flags & KEYSET_EMPTY )
620  fileErase( keysetInfoPtr->keysetFile->fileName );
621  }
622  }
623 
624  return( CRYPT_OK );
625  }
626 
627  /* Process attribute get/set/delete messages */
628  if( isAttributeMessage( message ) )
629  {
630  REQUIRES( message == MESSAGE_GETATTRIBUTE || \
631  message == MESSAGE_GETATTRIBUTE_S || \
632  message == MESSAGE_SETATTRIBUTE || \
633  message == MESSAGE_SETATTRIBUTE_S );
634 
635  /* If it's a keyset-specific attribute, forward it directly to
636  the low-level code */
637 #ifdef USE_LDAP
638  if( messageValue >= CRYPT_OPTION_KEYS_LDAP_OBJECTCLASS && \
639  messageValue <= CRYPT_OPTION_KEYS_LDAP_EMAILNAME )
640  {
641  REQUIRES( keysetInfoPtr->type == KEYSET_LDAP );
642 
643  if( message == MESSAGE_SETATTRIBUTE || \
644  message == MESSAGE_SETATTRIBUTE_S )
645  {
646  status = keysetInfoPtr->setAttributeFunction( keysetInfoPtr,
647  messageDataPtr, messageValue );
648  if( status == CRYPT_ERROR_INITED )
649  {
650  setErrorInfo( keysetInfoPtr, messageValue,
652  return( CRYPT_ERROR_INITED );
653  }
654  }
655  else
656  {
657  REQUIRES( message == MESSAGE_GETATTRIBUTE || \
658  message == MESSAGE_GETATTRIBUTE_S );
659 
660  status = keysetInfoPtr->getAttributeFunction( keysetInfoPtr,
661  messageDataPtr, messageValue );
662  if( status == CRYPT_ERROR_NOTFOUND )
663  {
664  setErrorInfo( keysetInfoPtr, messageValue,
666  return( CRYPT_ERROR_NOTFOUND );
667  }
668  }
669  return( status );
670  }
671 #endif /* USE_LDAP */
672 
673  if( message == MESSAGE_GETATTRIBUTE )
674  return( getKeysetAttribute( keysetInfoPtr,
675  ( int * ) messageDataPtr,
676  messageValue ) );
677  if( message == MESSAGE_GETATTRIBUTE_S )
678  return( getKeysetAttributeS( keysetInfoPtr,
679  ( MESSAGE_DATA * ) messageDataPtr,
680  messageValue ) );
681  if( message == MESSAGE_SETATTRIBUTE )
682  {
683  /* CRYPT_IATTRIBUTE_INITIALISED is purely a notification message
684  with no parameters so we don't pass it down to the attribute-
685  handling code */
686  if( messageValue == CRYPT_IATTRIBUTE_INITIALISED )
687  return( CRYPT_OK );
688 
689  return( setKeysetAttribute( keysetInfoPtr,
690  *( ( int * ) messageDataPtr ),
691  messageValue ) );
692  }
693  if( message == MESSAGE_SETATTRIBUTE_S )
694  {
695  const MESSAGE_DATA *msgData = ( MESSAGE_DATA * ) messageDataPtr;
696 
697  return( setKeysetAttributeS( keysetInfoPtr, msgData->data,
698  msgData->length, messageValue ) );
699  }
700 
701  retIntError();
702  }
703 
704  /* Process messages that check a keyset */
705  if( message == MESSAGE_CHECK )
706  {
707  /* The check for whether this keyset type can contain an object that
708  can perform the requested operation has already been performed by
709  the kernel so there's nothing further to do here */
710  REQUIRES( ( messageValue != MESSAGE_CHECK_PKC_PRIVATE && \
711  messageValue != MESSAGE_CHECK_PKC_DECRYPT && \
712  messageValue != MESSAGE_CHECK_PKC_DECRYPT_AVAIL && \
713  messageValue != MESSAGE_CHECK_PKC_SIGN && \
714  messageValue != MESSAGE_CHECK_PKC_SIGN_AVAIL ) ||
715  ( keysetInfoPtr->type != KEYSET_DBMS && \
716  keysetInfoPtr->type != KEYSET_LDAP && \
717  keysetInfoPtr->type != KEYSET_HTTP ) );
718 
719  return( CRYPT_OK );
720  }
721 
722  /* Process object-specific messages */
723  if( message == MESSAGE_KEY_GETKEY )
724  {
725  MESSAGE_KEYMGMT_INFO *getkeyInfo = \
726  ( MESSAGE_KEYMGMT_INFO * ) messageDataPtr;
727  CONST_INIT_STRUCT_3( KEYID_INFO keyIDinfo, \
728  getkeyInfo->keyIDtype, getkeyInfo->keyID, \
729  getkeyInfo->keyIDlength );
730  BYTE keyIDbuffer[ KEYID_SIZE + 8 ];
731 
732  CONST_SET_STRUCT( keyIDinfo.keyIDtype = getkeyInfo->keyIDtype; \
733  keyIDinfo.keyID = getkeyInfo->keyID; \
734  keyIDinfo.keyIDlength = getkeyInfo->keyIDlength );
735 
736  REQUIRES( keyIDinfo.keyIDtype != CRYPT_KEYID_NONE && \
737  keyIDinfo.keyID != NULL && \
738  keyIDinfo.keyIDlength >= MIN_NAME_LENGTH && \
739  keyIDinfo.keyIDlength < MAX_ATTRIBUTE_SIZE );
740  REQUIRES( messageValue != KEYMGMT_ITEM_PRIVATEKEY || \
741  keysetInfoPtr->type == KEYSET_FILE );
742  REQUIRES( ( messageValue != KEYMGMT_ITEM_SECRETKEY && \
743  messageValue != KEYMGMT_ITEM_DATA ) || \
744  ( keysetInfoPtr->type == KEYSET_FILE && \
745  keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS15 ) );
746  REQUIRES( ( messageValue != KEYMGMT_ITEM_REQUEST && \
747  messageValue != KEYMGMT_ITEM_REVREQUEST && \
748  messageValue != KEYMGMT_ITEM_REVOCATIONINFO && \
749  messageValue != KEYMGMT_ITEM_PKIUSER ) || \
750  keysetInfoPtr->type == KEYSET_DBMS );
751 
752  /* Get the key */
753  resetErrorInfo( keysetInfoPtr );
754  status = initKeysetUpdate( keysetInfoPtr, &keyIDinfo, keyIDbuffer,
755  KEYID_SIZE, TRUE );
756  if( cryptStatusError( status ) )
757  return( status );
758  return( keysetInfoPtr->getItemFunction( keysetInfoPtr,
759  &getkeyInfo->cryptHandle, messageValue,
760  keyIDinfo.keyIDtype, keyIDinfo.keyID,
761  keyIDinfo.keyIDlength, getkeyInfo->auxInfo,
762  &getkeyInfo->auxInfoLength,
763  getkeyInfo->flags ) );
764  }
765  if( message == MESSAGE_KEY_SETKEY )
766  {
767  MESSAGE_KEYMGMT_INFO *setkeyInfo = \
768  ( MESSAGE_KEYMGMT_INFO * ) messageDataPtr;
769 
770  REQUIRES( messageValue != KEYMGMT_ITEM_PRIVATEKEY || \
771  ( keysetInfoPtr->type == KEYSET_FILE && \
772  ( keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS15 || \
773  keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS12 ) ) );
774  REQUIRES( ( messageValue != KEYMGMT_ITEM_SECRETKEY && \
775  messageValue != KEYMGMT_ITEM_DATA && \
776  messageValue != KEYMGMT_ITEM_KEYMETADATA ) || \
777  ( keysetInfoPtr->type == KEYSET_FILE && \
778  keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS15 ) );
779  REQUIRES( ( messageValue != KEYMGMT_ITEM_REQUEST && \
780  messageValue != KEYMGMT_ITEM_REVREQUEST && \
781  messageValue != KEYMGMT_ITEM_REVOCATIONINFO && \
782  messageValue != KEYMGMT_ITEM_PKIUSER ) || \
783  ( keysetInfoPtr->type == KEYSET_DBMS ) );
784 
785  /* Set the key. This is currently the only way to associate a
786  certificate with a context (that is, it's not possible to add a
787  certificate to an existing context directly). At first glance
788  this should be possible since the required access checks are
789  performed by the kernel: The object is of the correct type (a
790  certificate), in the high state (it's been signed), and the
791  certificate owner and context owner are the same. However the
792  actual process of attaching the certificate to the context is
793  quite tricky. The certificate will have a public-key context
794  already attached to it from when the certificate was created or
795  imported. In order to attach this to the other context we'd need
796  to first destroy the context associated with the certificate and
797  then replace it with the other context, which is both messy and
798  non-atomic. There are also complications surrounding use with
799  devices, where contexts aren't really full cryptlib objects but
800  just dummy values that point back to the device for handling of
801  operations. Going via a keyset/device bypasses these issues, but
802  doing it directly shows up all of these problems */
803  resetErrorInfo( keysetInfoPtr );
804  status = initKeysetUpdate( keysetInfoPtr, NULL, NULL, 0, FALSE );
805  if( cryptStatusError( status ) )
806  return( status );
807  status = keysetInfoPtr->setItemFunction( keysetInfoPtr,
808  setkeyInfo->cryptHandle, messageValue,
809  setkeyInfo->auxInfo, setkeyInfo->auxInfoLength,
810  setkeyInfo->flags );
811  if( cryptStatusError( status ) )
812  return( status );
813 
814  /* The update succeeded, remember that the data in the keyset has
815  changed */
816  keysetInfoPtr->flags |= KEYSET_DIRTY;
817  keysetInfoPtr->flags &= ~KEYSET_EMPTY;
818 
819  return( CRYPT_OK );
820  }
821  if( message == MESSAGE_KEY_DELETEKEY )
822  {
823  MESSAGE_KEYMGMT_INFO *deletekeyInfo = \
824  ( MESSAGE_KEYMGMT_INFO * ) messageDataPtr;
825  CONST_INIT_STRUCT_3( KEYID_INFO keyIDinfo, \
826  deletekeyInfo->keyIDtype, deletekeyInfo->keyID, \
827  deletekeyInfo->keyIDlength );
828  BYTE keyIDbuffer[ KEYID_SIZE + 8 ];
829 
830  CONST_SET_STRUCT( keyIDinfo.keyIDtype = deletekeyInfo->keyIDtype; \
831  keyIDinfo.keyID = deletekeyInfo->keyID; \
832  keyIDinfo.keyIDlength = deletekeyInfo->keyIDlength );
833 
834  REQUIRES( keyIDinfo.keyIDtype != CRYPT_KEYID_NONE && \
835  keyIDinfo.keyID != NULL && \
836  keyIDinfo.keyIDlength >= MIN_NAME_LENGTH && \
837  keyIDinfo.keyIDlength < MAX_ATTRIBUTE_SIZE );
838 
839  /* Delete the key */
840  resetErrorInfo( keysetInfoPtr );
841  status = initKeysetUpdate( keysetInfoPtr, &keyIDinfo, keyIDbuffer,
842  KEYID_SIZE, FALSE );
843  if( cryptStatusError( status ) )
844  return( status );
845  status = keysetInfoPtr->deleteItemFunction( keysetInfoPtr,
846  messageValue, keyIDinfo.keyIDtype,
847  keyIDinfo.keyID, keyIDinfo.keyIDlength );
848  if( cryptStatusOK( status ) )
849  {
850  /* The update succeeded, remember that the data in the keyset
851  has changed */
852  keysetInfoPtr->flags |= KEYSET_DIRTY;
853  }
854  return( status );
855  }
856  if( message == MESSAGE_KEY_GETFIRSTCERT )
857  {
858  MESSAGE_KEYMGMT_INFO *getnextcertInfo = \
859  ( MESSAGE_KEYMGMT_INFO * ) messageDataPtr;
860  CONST_INIT_STRUCT_3( KEYID_INFO keyIDinfo, \
861  getnextcertInfo->keyIDtype, getnextcertInfo->keyID, \
862  getnextcertInfo->keyIDlength );
863  BYTE keyIDbuffer[ KEYID_SIZE + 8 ];
864 
865  CONST_SET_STRUCT( keyIDinfo.keyIDtype = getnextcertInfo->keyIDtype; \
866  keyIDinfo.keyID = getnextcertInfo->keyID; \
867  keyIDinfo.keyIDlength = getnextcertInfo->keyIDlength );
868 
869  REQUIRES( keyIDinfo.keyIDtype != CRYPT_KEYID_NONE && \
870  keyIDinfo.keyID != NULL && \
871  keyIDinfo.keyIDlength >= MIN_NAME_LENGTH && \
872  keyIDinfo.keyIDlength < MAX_ATTRIBUTE_SIZE );
873  REQUIRES( ( getnextcertInfo->auxInfo == NULL && \
874  getnextcertInfo->auxInfoLength == 0 ) || \
875  ( getnextcertInfo->auxInfo != NULL && \
876  getnextcertInfo->auxInfoLength == sizeof( int ) ) );
877 
878  /* Fetch the first certificate in a sequence from the keyset */
879  resetErrorInfo( keysetInfoPtr );
880  status = initKeysetUpdate( keysetInfoPtr, &keyIDinfo, keyIDbuffer,
881  KEYID_SIZE, TRUE );
882  if( cryptStatusError( status ) )
883  return( status );
884  return( keysetInfoPtr->getFirstItemFunction( keysetInfoPtr,
885  &getnextcertInfo->cryptHandle,
886  getnextcertInfo->auxInfo, messageValue,
887  keyIDinfo.keyIDtype, keyIDinfo.keyID,
888  keyIDinfo.keyIDlength,
889  getnextcertInfo->flags ) );
890  }
891  if( message == MESSAGE_KEY_GETNEXTCERT )
892  {
893  MESSAGE_KEYMGMT_INFO *getnextcertInfo = \
894  ( MESSAGE_KEYMGMT_INFO * ) messageDataPtr;
895 
896  REQUIRES( getnextcertInfo->keyIDtype == CRYPT_KEYID_NONE && \
897  getnextcertInfo->keyID == NULL && \
898  getnextcertInfo->keyIDlength == 0 );
899  REQUIRES( ( getnextcertInfo->auxInfo == NULL && \
900  getnextcertInfo->auxInfoLength == 0 ) || \
901  ( getnextcertInfo->auxInfo != NULL && \
902  getnextcertInfo->auxInfoLength == sizeof( int ) ) );
903  REQUIRES( getnextcertInfo->flags >= KEYMGMT_FLAG_NONE && \
904  getnextcertInfo->flags < KEYMGMT_FLAG_MAX && \
905  ( getnextcertInfo->flags & ~KEYMGMT_MASK_CERTOPTIONS ) == 0 );
906 
907  /* Fetch the next certificate in a sequence from the keyset */
908  return( keysetInfoPtr->getNextItemFunction( keysetInfoPtr,
909  &getnextcertInfo->cryptHandle,
910  getnextcertInfo->auxInfo,
911  getnextcertInfo->flags ) );
912  }
913 #ifdef USE_DBMS
914  if( message == MESSAGE_KEY_CERTMGMT )
915  {
916  MESSAGE_CERTMGMT_INFO *certMgmtInfo = \
917  ( MESSAGE_CERTMGMT_INFO * ) messageDataPtr;
918 
919  REQUIRES( messageValue >= CRYPT_CERTACTION_CERT_CREATION && \
920  messageValue <= CRYPT_CERTACTION_LAST_USER );
921 
922  /* Perform the certificate management operation */
923  resetErrorInfo( keysetInfoPtr );
924  status = initKeysetUpdate( keysetInfoPtr, NULL, NULL, 0, TRUE );
925  if( cryptStatusError( status ) )
926  return( status );
927  status = keysetInfoPtr->keysetDBMS->certMgmtFunction( keysetInfoPtr,
928  ( certMgmtInfo->cryptCert != CRYPT_UNUSED ) ? \
929  &certMgmtInfo->cryptCert : NULL,
930  certMgmtInfo->caKey, certMgmtInfo->request,
931  messageValue );
932  if( cryptStatusOK( status ) )
933  {
934  /* The update succeeded, remember that the data in the keyset has
935  changed */
936  keysetInfoPtr->flags |= KEYSET_DIRTY;
937  }
938  return( status );
939  }
940 #endif /* USE_DBMS */
941 
942  retIntError();
943  }
944 
945 /* Open a keyset. This is a low-level function encapsulated by createKeyset()
946  and used to manage error exits */
947 
948 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 7 ) ) \
949 static int openKeyset( OUT_HANDLE_OPT CRYPT_KEYSET *iCryptKeyset,
952  IN_BUFFER( nameLength ) const char *name,
953  IN_LENGTH_SHORT_MIN( MIN_NAME_LENGTH ) const int nameLength,
954  IN_ENUM_OPT( CRYPT_KEYOPT ) const CRYPT_KEYOPT_TYPE options,
955  OUT_PTR KEYSET_INFO **keysetInfoPtrPtr )
956  {
957  KEYSET_INFO *keysetInfoPtr;
958  STREAM stream;
959  CRYPT_KEYOPT_TYPE localOptions = options;
960  KEYSET_SUBTYPE keysetSubType = DUMMY_INIT;
961  OBJECT_SUBTYPE subType;
962  int storageSize, status;
963 
964  assert( isWritePtr( iCryptKeyset, sizeof( CRYPT_KEYSET ) ) );
965  assert( isReadPtr( name, nameLength ) );
966  assert( isWritePtr( keysetInfoPtrPtr, sizeof( KEYSET_INFO * ) ) );
967 
968  REQUIRES( ( iCryptOwner == DEFAULTUSER_OBJECT_HANDLE ) || \
969  isHandleRangeValid( iCryptOwner ) );
970  REQUIRES( keysetType > CRYPT_KEYSET_NONE && \
971  keysetType < CRYPT_KEYSET_LAST );
972  REQUIRES( nameLength >= MIN_NAME_LENGTH && \
973  nameLength < MAX_ATTRIBUTE_SIZE );
974  REQUIRES( options >= CRYPT_KEYOPT_NONE && options < CRYPT_KEYOPT_LAST );
975 
976  /* Clear the return values */
977  *iCryptKeyset = CRYPT_ERROR;
978  *keysetInfoPtrPtr = NULL;
979 
980  /* Perform general checks that can be done before we create the object */
981  if( ( keysetType == CRYPT_KEYSET_HTTP && \
982  options != CRYPT_KEYOPT_READONLY ) || \
983  ( keysetType == CRYPT_KEYSET_LDAP && \
984  options == CRYPT_KEYOPT_CREATE ) )
985  {
986  /* We can't open an HTTP keyset for anything other than read-only
987  access, and we can't create an LDAP directory */
988  return( CRYPT_ERROR_PERMISSION );
989  }
990  if( keysetType == CRYPT_KEYSET_FILE && nameLength > MAX_PATH_LENGTH - 1 )
991  return( CRYPT_ARGERROR_STR1 );
992 
993  /* Set up subtype-specific information */
994  switch( keysetType )
995  {
996  case CRYPT_KEYSET_FILE:
998  storageSize = sizeof( FILE_INFO );
999  break;
1000 
1001  case CRYPT_KEYSET_HTTP:
1002  subType = SUBTYPE_KEYSET_HTTP;
1003  storageSize = sizeof( HTTP_INFO );
1004  break;
1005 
1006  case CRYPT_KEYSET_LDAP:
1007  subType = SUBTYPE_KEYSET_LDAP;
1008  storageSize = sizeof( LDAP_INFO );
1009  break;
1010 
1011  case CRYPT_KEYSET_ODBC:
1012  case CRYPT_KEYSET_DATABASE:
1013  subType = SUBTYPE_KEYSET_DBMS;
1014  storageSize = sizeof( DBMS_INFO );
1015  break;
1016 
1019  subType = SUBTYPE_KEYSET_DBMS_STORE;
1020  storageSize = sizeof( DBMS_INFO );
1021  break;
1022 
1023  default:
1024  retIntError();
1025  }
1026 
1027  /* Handle compiler warnings of uninitialised variables, unfortunately
1028  since it's non-scalar data we can't do this with the usual
1029  DUMMY_INIT */
1030  memset( &stream, 0, sizeof( STREAM ) );
1031 
1032  /* If it's a flat-file keyset which is implemented on top of an I/O
1033  stream make sure that we can open the stream before we try and
1034  create the keyset object */
1035  if( keysetType == CRYPT_KEYSET_FILE )
1036  {
1037  BOOLEAN isReadOnly;
1038 
1039  status = openKeysetStream( &stream, name, nameLength, options,
1040  &isReadOnly, &keysetSubType );
1041  if( cryptStatusError( status ) )
1042  return( status );
1043 
1044  /* If we tried to open the file in read/write mode and it's
1045  read-only, change the access mode to read-only */
1046  if( isReadOnly )
1047  localOptions = CRYPT_KEYOPT_READONLY;
1048 
1049  /* If the keyset contains the full set of search keys and index
1050  information needed to handle all keyset operations (e.g.
1051  certificate chain building, query by key usage types) we mark it
1052  as a full-function keyset with the same functionality as a DBMS
1053  keyset rather than just a generic flat-file store */
1054  if( keysetSubType == KEYSET_SUBTYPE_PKCS15 )
1055  subType = SUBTYPE_KEYSET_FILE;
1056 
1057  /* If it's a limited keyset type that nonetheless allows writing
1058  at least one public/private key, mark it as a restricted-function
1059  keyset */
1060  if( keysetSubType == KEYSET_SUBTYPE_PKCS12 )
1061  subType = SUBTYPE_KEYSET_FILE_PARTIAL;
1062 
1063  /* Make sure that the open-mode that's been specified is compatible
1064  with the object subtype */
1065  switch( subType )
1066  {
1067  case SUBTYPE_KEYSET_FILE:
1068  /* All access modes allowed */
1069  break;
1070 
1072  /* Update access not allowed */
1073  if( options != CRYPT_KEYOPT_READONLY && \
1074  options != CRYPT_KEYOPT_CREATE )
1075  return( CRYPT_ARGERROR_NUM2 );
1076  break;
1077 
1079  /* Only read access allowed */
1080  if( options != CRYPT_KEYOPT_READONLY )
1081  return( CRYPT_ARGERROR_NUM2 );
1082  break;
1083 
1084  default:
1085  retIntError();
1086  }
1087  }
1088 
1089  /* Create the keyset object */
1090  status = krnlCreateObject( iCryptKeyset, ( void ** ) &keysetInfoPtr,
1091  sizeof( KEYSET_INFO ) + storageSize,
1092  OBJECT_TYPE_KEYSET, subType,
1093  CREATEOBJECT_FLAG_NONE, iCryptOwner,
1094  ACTION_PERM_NONE_ALL, keysetMessageFunction );
1095  if( cryptStatusError( status ) )
1096  {
1097  if( keysetType == CRYPT_KEYSET_FILE )
1098  sFileClose( &stream );
1099  return( status );
1100  }
1101  ANALYSER_HINT( keysetInfoPtr != NULL );
1102  *keysetInfoPtrPtr = keysetInfoPtr;
1103  keysetInfoPtr->objectHandle = *iCryptKeyset;
1104  keysetInfoPtr->ownerHandle = iCryptOwner;
1105  keysetInfoPtr->options = localOptions;
1106  switch( keysetType )
1107  {
1108  case CRYPT_KEYSET_FILE:
1109  keysetInfoPtr->type = KEYSET_FILE;
1110  keysetInfoPtr->keysetFile = ( FILE_INFO * ) keysetInfoPtr->storage;
1111  break;
1112 
1113 #ifdef USE_HTTP
1114  case CRYPT_KEYSET_HTTP:
1115  keysetInfoPtr->type = KEYSET_HTTP;
1116  keysetInfoPtr->keysetHTTP = ( HTTP_INFO * ) keysetInfoPtr->storage;
1117  break;
1118 #endif /* USE_HTTP */
1119 
1120 #ifdef USE_LDAP
1121  case CRYPT_KEYSET_LDAP:
1122  keysetInfoPtr->type = KEYSET_LDAP;
1123  keysetInfoPtr->keysetLDAP = ( LDAP_INFO * ) keysetInfoPtr->storage;
1124  break;
1125 #endif /* USE_LDAP */
1126 
1127 #ifdef USE_DBMS
1128  default:
1129  keysetInfoPtr->type = KEYSET_DBMS;
1130  keysetInfoPtr->keysetDBMS = ( DBMS_INFO * ) keysetInfoPtr->storage;
1131  break;
1132 #endif /* USE_DBMS */
1133  }
1134  keysetInfoPtr->storageSize = storageSize;
1135 
1136  /* If it's a flat-file keyset which is implemented on top of an I/O
1137  stream, handle it specially */
1138  if( keysetType == CRYPT_KEYSET_FILE )
1139  {
1140  status = completeKeysetFileOpen( keysetInfoPtr, keysetSubType,
1141  &stream, name, nameLength );
1142  if( cryptStatusError( status ) )
1143  {
1144  sFileClose( &keysetInfoPtr->keysetFile->stream );
1145  if( options == CRYPT_KEYOPT_CREATE )
1146  {
1147  /* It's a newly-created file, make sure that we don't leave
1148  it lying around on disk */
1149  fileErase( keysetInfoPtr->keysetFile->fileName );
1150  }
1151  return( status );
1152  }
1153 
1154  return( CRYPT_OK );
1155  }
1156 
1157  /* Wait for any async keyset driver binding to complete. We do this as
1158  late as possible to prevent file keyset reads that occur on startup
1159  (for example to get configuration options) from stalling the startup
1160  process */
1162  {
1163  /* The kernel is shutting down, bail out */
1164  DEBUG_DIAG(( "Exiting due to kernel shutdown" ));
1165  assert( DEBUG_WARN );
1166  return( CRYPT_ERROR_PERMISSION );
1167  }
1168 
1169  /* It's a specific type of keyset, set up the access information for it
1170  and connect to it */
1171  switch( keysetType )
1172  {
1173  case CRYPT_KEYSET_ODBC:
1174  case CRYPT_KEYSET_DATABASE:
1177  status = setAccessMethodDBMS( keysetInfoPtr, keysetType );
1178  break;
1179 
1180  case CRYPT_KEYSET_HTTP:
1181  status = setAccessMethodHTTP( keysetInfoPtr );
1182  break;
1183 
1184  case CRYPT_KEYSET_LDAP:
1185  status = setAccessMethodLDAP( keysetInfoPtr );
1186  break;
1187 
1188  default:
1189  retIntError();
1190  }
1191  if( cryptStatusError( status ) )
1192  return( status );
1193  ENSURES( keysetInfoPtr->initFunction != NULL && \
1194  keysetInfoPtr->shutdownFunction != NULL && \
1195  keysetInfoPtr->getItemFunction != NULL );
1196  ENSURES( keysetType == CRYPT_KEYSET_HTTP || \
1197  ( keysetInfoPtr->setItemFunction != NULL && \
1198  keysetInfoPtr->deleteItemFunction != NULL && \
1199  keysetInfoPtr->isBusyFunction != NULL ) );
1200  ENSURES( keysetType == CRYPT_KEYSET_HTTP || \
1201  keysetType == CRYPT_KEYSET_LDAP || \
1202  ( keysetInfoPtr->getFirstItemFunction != NULL && \
1203  keysetInfoPtr->getNextItemFunction != NULL ) );
1204 #ifdef USE_LDAP
1205  ENSURES( keysetType != CRYPT_KEYSET_LDAP || \
1206  ( keysetInfoPtr->getAttributeFunction != NULL && \
1207  keysetInfoPtr->setAttributeFunction != NULL ) );
1208 #endif /* USE_LDAP */
1209 
1210  /* Initialise keyset access */
1211  status = keysetInfoPtr->initFunction( keysetInfoPtr, name, nameLength,
1212  keysetInfoPtr->options );
1213  if( cryptStatusOK( status ) )
1214  {
1215  keysetInfoPtr->flags |= KEYSET_OPEN;
1216  if( keysetInfoPtr->options == CRYPT_KEYOPT_CREATE )
1217  keysetInfoPtr->flags |= KEYSET_EMPTY;
1218  }
1219  return( status );
1220  }
1221 
1222 /* Create a keyset object */
1223 
1224 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
1225 int createKeyset( INOUT MESSAGE_CREATEOBJECT_INFO *createInfo,
1226  STDC_UNUSED const void *auxDataPtr,
1227  STDC_UNUSED const int auxValue )
1228  {
1230  KEYSET_INFO *keysetInfoPtr = NULL;
1231  int initStatus, status;
1232 
1233  assert( isWritePtr( createInfo, sizeof( MESSAGE_CREATEOBJECT_INFO ) ) );
1234 
1235  REQUIRES( auxDataPtr == NULL && auxValue == 0 );
1236  REQUIRES( createInfo->arg1 > CRYPT_KEYSET_NONE && \
1237  createInfo->arg1 < CRYPT_KEYSET_LAST );
1238  REQUIRES( createInfo->arg2 >= CRYPT_KEYOPT_NONE && \
1239  createInfo->arg2 < CRYPT_KEYOPT_LAST );
1240  REQUIRES( createInfo->strArgLen1 >= MIN_NAME_LENGTH && \
1241  createInfo->strArgLen1 < MAX_ATTRIBUTE_SIZE );
1242 
1243  /* Pass the call on to the lower-level open function */
1244  initStatus = openKeyset( &iCryptKeyset, createInfo->cryptOwner,
1245  createInfo->arg1, createInfo->strArg1,
1246  createInfo->strArgLen1, createInfo->arg2,
1247  &keysetInfoPtr );
1248  if( cryptStatusError( initStatus ) )
1249  {
1250  /* If the create object failed, return immediately */
1251  if( keysetInfoPtr == NULL )
1252  return( initStatus );
1253 
1254  /* The init failed, make sure that the object gets destroyed when we
1255  notify the kernel that the setup process is complete */
1256  krnlSendNotifier( iCryptKeyset, IMESSAGE_DESTROY );
1257  }
1258 
1259  /* We've finished setting up the object-type-specific info, tell the
1260  kernel that the object is ready for use */
1261  status = krnlSendMessage( iCryptKeyset, IMESSAGE_SETATTRIBUTE,
1262  MESSAGE_VALUE_OK, CRYPT_IATTRIBUTE_STATUS );
1263  if( cryptStatusError( initStatus ) || cryptStatusError( status ) )
1264  return( cryptStatusError( initStatus ) ? initStatus : status );
1265  createInfo->cryptHandle = iCryptKeyset;
1266  return( CRYPT_OK );
1267  }
1268 
1269 /* Generic management function for this class of object */
1270 
1271 CHECK_RETVAL \
1272 int keysetManagementFunction( IN_ENUM( MANAGEMENT_ACTION ) \
1273  const MANAGEMENT_ACTION_TYPE action )
1274  {
1275  static int initLevel = 0;
1276  int status;
1277 
1278  REQUIRES( action == MANAGEMENT_ACTION_INIT || \
1279  action == MANAGEMENT_ACTION_SHUTDOWN );
1280 
1281  switch( action )
1282  {
1284  status = dbxInitODBC();
1285  if( cryptStatusOK( status ) )
1286  {
1287  initLevel++;
1288  if( krnlIsExiting() )
1289  {
1290  /* The kernel is shutting down, exit */
1291  return( CRYPT_ERROR_PERMISSION );
1292  }
1293  status = dbxInitLDAP();
1294  }
1295  if( cryptStatusOK( status ) )
1296  initLevel++;
1297  return( status );
1298 
1300  if( initLevel > 1 )
1301  dbxEndLDAP();
1302  if( initLevel > 0 )
1303  dbxEndODBC();
1304  initLevel = 0;
1305  return( CRYPT_OK );
1306  }
1307 
1308  retIntError();
1309  }
1310 #endif /* USE_KEYSETS */