cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
dbms.h
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib DBMS Interface *
4 * Copyright Peter Gutmann 1996-2008 *
5 * *
6 ****************************************************************************/
7 
8 #include <stdarg.h>
9 #if defined( INC_ALL )
10  #include "crypt.h"
11  #include "keyset.h"
12 #else
13  #include "crypt.h"
14  #include "keyset/keyset.h"
15 #endif /* Compiler-specific includes */
16 
17 /* The size of the ID fields, derived from the base64-encoded first 128 bits
18  of an SHA-1 hash. The field size value is also given in text form for
19  use in SQL strings */
20 
21 #define DBXKEYID_SIZE 16 /* Full keyID = 128 bits */
22 #define ENCODED_DBXKEYID_SIZE 22 /* base64-encoded key ID */
23 #define TEXT_DBXKEYID_SIZE "22"
24 
25 /* The maximum SQL query size */
26 
27 #define MAX_SQL_QUERY_SIZE 256
28 
29 /* When performing a query the database glue code limits the maximum returned
30  data size to a certain size, the following define allows us to declare a
31  fixed-size buffer that we know will always be big enough */
32 
33 #define MAX_QUERY_RESULT_SIZE MAX_ENCODED_CERT_SIZE
34 
35 /* Database status flags. These are:
36 
37  FLAG_BINARYBLOBS: Database supports binary blobs.
38 
39  FLAG_CERTSTORE/FLAG_CERTSTORE_FIELDS: Certificate stores are designated
40  by two flags, a main one for standard database/certificate store
41  differentiation and a secondary one that indicates that it's a
42  certificate store opened as a standard database, for example
43  when it's being used for read-only access with a key server. In
44  this case it's possible to perform extended queries on fields
45  that aren't present in standard databases so we set the
46  secondary flags to indicate that extended queries are possible
47  even though certificate store functionality isn't present.
48 
49  FLAG_QUERYACTIVE: A query (returning a multiple-element result set) is
50  currently in progress.
51 
52  FLAG_UPDATEACTIVE: An update is currently in progress. This is required
53  because we can sometimes run into a situation where an update
54  falls through to an abort without ever having been begun, this
55  happens if there's a sequence of miscellaneous setup operations
56  taking place and one of them fails before we begin the update.
57  Although it'd be better if the caller handled this, in practice
58  it'd mean passing extra status information (failed vs.failed but
59  need to abort a commenced update) across a number of different
60  functions, to avoid this we record whether an update has begun
61  and if not skip an abort operation if there's no update currently
62  in progress */
63 
64 #define DBMS_FLAG_NONE 0x00 /* No DBMS flag */
65 #define DBMS_FLAG_BINARYBLOBS 0x01 /* DBMS supports blobs */
66 #define DBMS_FLAG_UPDATEACTIVE 0x02 /* Ongoing update in progress */
67 #define DBMS_FLAG_QUERYACTIVE 0x04 /* Ongoing query in progress */
68 #define DBMS_FLAG_CERTSTORE 0x08 /* Full certificate store */
69 #define DBMS_FLAG_CERTSTORE_FIELDS 0x10 /* Certificate store fields */
70 #define DBMS_FLAG_MAX 0x1F /* Maximum possible flag value */
71 
72 /* Database feature information returned when the keyset is opened */
73 
74 #define DBMS_FEATURE_FLAG_NONE 0x00 /* No DBMS features */
75 #define DBMS_FEATURE_FLAG_BINARYBLOBS 0x01 /* DBMS supports binary blobs */
76 #define DBMS_FEATURE_FLAG_READONLY 0x02 /* DBMS doesn't allow write access */
77 #define DBMS_FEATURE_FLAG_PRIVILEGES 0x04 /* DBMS supports GRANT/REVOKE */
78 #define DBMS_FEATURE_FLAG_MAX 0x07 /* Maximum possible flag value */
79 
80 /* The certstore and binary blobs flags are checked often enough that we
81  define a macro for them */
82 
83 #define hasBinaryBlobs( dbmsInfo ) \
84  ( ( dbmsInfo )->flags & DBMS_FLAG_BINARYBLOBS )
85 #define isCertStore( dbmsInfo ) \
86  ( ( dbmsInfo )->flags & DBMS_FLAG_CERTSTORE )
87 
88 /* When we add or read information to/from a table we sometimes have to
89  specify type information which is an integer value, however SQL requires
90  that things be set out as character strings so we use the following
91  defines to provide the string form of the value for insertion into an SQL
92  query. Unfortunately we can't check this at compile time so we have to
93  check it via an assertion in the CA dispatch function */
94 
95 #define TEXT_CERTTYPE_REQUEST_CERT "5"
96 #define TEXT_CERTTYPE_REQUEST_REVOCATION "6"
97 
98 #define TEXT_CERTACTION_CREATE "1"
99 #define TEXTCH_CERTACTION_ADDUSER '5'
100 #define TEXT_CERTACTION_REQUEST_CERT "7"
101 #define TEXTCH_CERTACTION_REQUEST_CERT '7'
102 #define TEXT_CERTACTION_REQUEST_RENEWAL "8"
103 #define TEXTCH_CERTACTION_REQUEST_RENEWAL '8'
104 #define TEXT_CERTACTION_CERT_CREATION "10"
105 
106 /* Special escape strings used in database keys to indicate that the value is
107  physically but not logically present. This is used to handle (currently-)
108  incomplete certificate issues and similar events where intermediate state
109  information has to be stored in the database but the object in question
110  isn't ready for use yet */
111 
112 #define KEYID_ESC1 "--"
113 #define KEYID_ESC2 "##"
114 #define KEYID_ESC_SIZE 2
115 
116 /* The ways in which we can add a certificate object to a table. Normally
117  we just add the certificate as is, however if we're awaiting confirmation
118  from a user before we can complete the certificate issue process we
119  perform a partial add that marks the certificate as not quite ready for
120  use yet. A variant of this is when we're renewing a certificate (i.e.
121  re-issuing it with the same key, which is really bad but required by some
122  certificate mismanagement protocols) in which case we have to process the
123  update as a multi-stage process because we're replacing an existing
124  certificate with one which is exactly the same as far as the uniqueness
125  constraints on the certificate store are concerned */
126 
127 typedef enum {
128  CERTADD_NONE, /* No certificate-add operation */
129  CERTADD_NORMAL, /* Standard one-step add */
130  CERTADD_PARTIAL, /* Partial add */
131  CERTADD_PARTIAL_RENEWAL, /* Partial add with certificate replacement to follow */
132  CERTADD_RENEWAL_COMPLETE, /* Completion of renewal */
133  CERTADD_LAST /* Last valid certificate-add type */
134  } CERTADD_TYPE;
135 
136 /* In order to make reporting of parameter errors in the multi-parameter
137  CA management function easier we provide symbolic defines mapping the
138  CA management-specific parameter type to its corresponding parameter
139  error type */
140 
141 #define CAMGMT_ARGERROR_CAKEY CRYPT_ARGERROR_NUM1
142 #define CAMGMT_ARGERROR_REQUEST CRYPT_ARGERROR_NUM2
143 #define CAMGMT_ARGERROR_ACTION CRYPT_ARGERROR_VALUE
144 
145 /* A structure to parse the database access information into so that it can
146  be used by backend-specific connect functions */
147 
148 typedef struct {
149  BUFFER( CRYPT_MAX_TEXTSIZE, userLen ) \
150  char userBuffer[ CRYPT_MAX_TEXTSIZE + 8 ];
151  BUFFER_OPT( CRYPT_MAX_TEXTSIZE, userLen ) \
152  char *user;
154  char passwordBuffer[ CRYPT_MAX_TEXTSIZE + 8 ];
156  char *password;
157  BUFFER( CRYPT_MAX_TEXTSIZE, serverLen ) \
158  char serverBuffer[ CRYPT_MAX_TEXTSIZE + 8 ];
159  BUFFER_OPT( CRYPT_MAX_TEXTSIZE, serverLen ) \
160  char *server;
162  char nameBuffer[ CRYPT_MAX_TEXTSIZE + 8 ];
164  char *name;
165  int userLen, passwordLen, serverLen, nameLen;
166  } DBMS_NAME_INFO;
167 
168 /* To avoid SQL injection attacks and speed up performance we make extensive
169  use of bound parameters. The following structure is used to communicate
170  these parameters to the database back-end */
171 
172 typedef enum {
173  BOUND_DATA_NONE, /* No bound data type */
174  BOUND_DATA_STRING, /* Character string */
175  BOUND_DATA_BLOB, /* Binary string */
176  BOUND_DATA_TIME, /* Date/time */
177  BOUND_DATA_LAST /* Last bound data type */
178  } BOUND_DATA_TYPE;
179 
180 typedef struct {
181  BOUND_DATA_TYPE type; /* Type of this data item */
183  const void *data; /* Data and data length */
185  } BOUND_DATA;
186 
187 #define BOUND_DATA_MAXITEMS 16
188 
189 /* Macros to initialise the bound-data information. When we're binding
190  standard data values (i.e. non-blob data) the buffer to contain the value
191  is always present but if there's no data in it then the length will be
192  zero, so we perform a check for a buffer with a length of zero and set
193  the buffer pointer to NULL if this is the case */
194 
195 #define initBoundData( boundData ) \
196  memset( ( boundData ), 0, sizeof( BOUND_DATA ) * BOUND_DATA_MAXITEMS )
197 #define setBoundData( bdStorage, bdIndex, bdValue, bdValueLen ) \
198  { \
199  const int bdLocalIndex = ( bdIndex ); \
200  \
201  ( bdStorage )[ bdLocalIndex ].type = BOUND_DATA_STRING; \
202  ( bdStorage )[ bdLocalIndex ].data = ( bdValueLen > 0 ) ? bdValue : NULL; \
203  ( bdStorage )[ bdLocalIndex ].dataLength = bdValueLen; \
204  }
205 #define setBoundDataBlob( bdStorage, bdIndex, bdValue, bdValueLen ) \
206  { \
207  const int bdLocalIndex = ( bdIndex ); \
208  \
209  ( bdStorage )[ bdLocalIndex ].type = BOUND_DATA_BLOB; \
210  ( bdStorage )[ bdLocalIndex ].data = bdValue; \
211  ( bdStorage )[ bdLocalIndex ].dataLength = bdValueLen; \
212  }
213 #define setBoundDataDate( bdStorage, bdIndex, bdValue ) \
214  { \
215  const int bdLocalIndex = ( bdIndex ); \
216  \
217  ( bdStorage )[ bdLocalIndex ].type = BOUND_DATA_TIME; \
218  ( bdStorage )[ bdLocalIndex ].data = bdValue; \
219  ( bdStorage )[ bdLocalIndex ].dataLength = sizeof( time_t ); \
220  }
221 
222 /****************************************************************************
223 * *
224 * DBMS Access Macros *
225 * *
226 ****************************************************************************/
227 
228 /* Macros to make use of the DBMS access functions less painful. These
229  assume the existence of a variable 'dbmsInfo' that contains DBMS access
230  state information */
231 
232 #define dbmsOpen( name, nameLen, options, featureFlags ) \
233  dbmsInfo->openDatabaseFunction( dbmsInfo, name, nameLen, options, featureFlags )
234 #define dbmsClose() \
235  dbmsInfo->closeDatabaseFunction( dbmsInfo )
236 #define dbmsStaticUpdate( command ) \
237  dbmsInfo->performStaticUpdateFunction( dbmsInfo, command )
238 #define dbmsUpdate( command, updateBoundData, updateType ) \
239  dbmsInfo->performUpdateFunction( dbmsInfo, command, updateBoundData, \
240  updateType )
241 #define dbmsStaticQuery( command, queryEntry, queryType ) \
242  dbmsInfo->performStaticQueryFunction( dbmsInfo, command, queryEntry, \
243  queryType )
244 #define dbmsQuery( command, data, dataMaxLength, dataLength, queryBoundData, queryEntry, queryType ) \
245  dbmsInfo->performQueryFunction( dbmsInfo, command, data, dataMaxLength, \
246  dataLength, queryBoundData, queryEntry, \
247  queryType )
248 
249 #ifdef USE_RPCAPI
250 int cmdClose( void *stateInfo, COMMAND_INFO *cmd );
251 int cmdGetErrorInfo( void *stateInfo, COMMAND_INFO *cmd );
252 int cmdOpen( void *stateInfo, COMMAND_INFO *cmd );
253 int cmdQuery( void *stateInfo, COMMAND_INFO *cmd );
254 int cmdUpdate( void *stateInfo, COMMAND_INFO *cmd );
255 #endif /* USE_RPCAPI */
256 
257 /* In order to provide access to the backend-specific error information for
258  the cryptlib error message-formatting routines we need to dig down into
259  the DBMS state structure to extract the error information */
260 
261 #define getDbmsErrorInfo( dbmsInfo ) \
262  ( &( ( ( DBMS_STATE_INFO * ) ( dbmsInfo )->stateInfo )->errorInfo ) )
263 
264 /* Other non-macro functions */
265 
266 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
267 int dbmsFormatQuery( OUT_BUFFER( outMaxLength, *outLength ) char *output,
268  IN_LENGTH_SHORT const int outMaxLength,
270  IN_BUFFER( inputLength ) const char *input,
272 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
273 int dbmsParseName( INOUT DBMS_NAME_INFO *nameInfo,
274  IN_BUFFER( nameLen ) const char *name,
275  IN_LENGTH_NAME const int nameLen );
276 
277 /****************************************************************************
278 * *
279 * DBMS Functions *
280 * *
281 ****************************************************************************/
282 
283 /* Prototypes for interface routines in dbms.c */
284 
286 int initDbxSession( INOUT KEYSET_INFO *keysetInfoPtr,
288 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
289 int endDbxSession( INOUT KEYSET_INFO *keysetInfoPtr );
290 
291 /* Prototypes for functions in dbx_rd.c/dbx_wr.c */
292 
293 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 9 ) ) \
294 int getItemData( INOUT DBMS_INFO *dbmsInfo,
296  OUT_OPT int *stateInfo,
297  IN_ENUM_OPT( KEYMGMT_ITEM ) const KEYMGMT_ITEM_TYPE itemType,
298  IN_ENUM_OPT( CRYPT_KEYID ) const CRYPT_KEYID_TYPE keyIDtype,
299  IN_BUFFER_OPT( keyValueLength ) const char *keyValue,
301  IN_FLAGS_Z( KEYMGMT ) const int options,
303 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 6 ) ) \
304 int addCert( INOUT DBMS_INFO *dbmsInfo,
306  IN_ENUM( CRYPT_CERTTYPE ) const CRYPT_CERTTYPE_TYPE certType,
307  IN_ENUM( CERTADD ) const CERTADD_TYPE addType,
308  IN_ENUM( DBMS_UPDATE ) const DBMS_UPDATE_TYPE updateType,
310 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 5 ) ) \
311 int addCRL( INOUT DBMS_INFO *dbmsInfo,
314  IN_ENUM( DBMS_UPDATE ) const DBMS_UPDATE_TYPE updateType,
317 int initDBMSread( INOUT KEYSET_INFO *keysetInfoPtr );
319 int initDBMSwrite( INOUT KEYSET_INFO *keysetInfoPtr );
320 
321 /* Prototypes for routines in dbx_misc.c */
322 
323 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
324 int makeKeyID( OUT_BUFFER( keyIdMaxLen, *keyIdLen ) char *keyID,
325  IN_LENGTH_SHORT_MIN( 16 ) const int keyIdMaxLen,
328  IN_BUFFER( idValueLength ) const void *idValue,
330 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
331 int getKeyID( OUT_BUFFER( keyIdMaxLen, *keyIdLen ) char *keyID,
332  IN_LENGTH_SHORT_MIN( 16 ) const int keyIdMaxLen,
333  OUT_LENGTH_SHORT_Z int *keyIdLen,
335  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE keyIDtype );
336 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
337 int getCertKeyID( OUT_BUFFER( keyIdMaxLen, *keyIdLen ) char *keyID,
338  IN_LENGTH_SHORT_MIN( 16 ) const int keyIdMaxLen,
339  OUT_LENGTH_SHORT_Z int *keyIdLen,
341 CHECK_RETVAL STDC_NONNULL_ARG( ( 3, 5 ) ) \
342 int extractCertData( IN_HANDLE const CRYPT_CERTIFICATE iCryptCert,
343  IN_INT const int formatType,
344  OUT_BUFFER( certDataMaxLength, *certDataLength ) \
345  void *certDataBuffer,
347  const int certDataMaxLength,
349 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
350 int resetErrorInfo( INOUT DBMS_INFO *dbmsInfo );
351 CHECK_RETVAL_PTR \
352 char *getKeyName( IN_ENUM( CRYPT_KEYID ) const CRYPT_KEYID_TYPE keyIDtype );
353 
354 /* Prototypes for routines in ca_add.c */
355 
356 CHECK_RETVAL_BOOL \
358  IN_ENUM( CRYPT_CERTACTION ) \
359  const CRYPT_CERTACTION_TYPE action );
360 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 6 ) ) \
361 int caAddCertRequest( INOUT DBMS_INFO *dbmsInfo,
362  IN_HANDLE const CRYPT_CERTIFICATE iCertRequest,
363  IN_ENUM( CRYPT_CERTTYPE ) \
364  const CRYPT_CERTTYPE_TYPE requestType,
367 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
368 int caAddPKIUser( INOUT DBMS_INFO *dbmsInfo,
371 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
372 int caDeletePKIUser( INOUT DBMS_INFO *dbmsInfo,
373  IN_ENUM( CRYPT_KEYID ) const CRYPT_KEYID_TYPE keyIDtype,
374  IN_BUFFER( keyIDlength ) const void *keyID,
377 
378 /* Prototypes for routines in ca_clean.c */
379 
380 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
381 int caCleanup( INOUT DBMS_INFO *dbmsInfo,
382  IN_ENUM( CRYPT_CERTACTION ) const CRYPT_CERTACTION_TYPE action,
384 
385 /* Prototypes for routines in ca_issue.c */
386 
387 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
388 int completeCertRenewal( INOUT DBMS_INFO *dbmsInfo,
391 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 6 ) ) \
392 int caIssueCert( INOUT DBMS_INFO *dbmsInfo,
395  IN_HANDLE const CRYPT_CERTIFICATE iCertRequest,
396  IN_ENUM( CRYPT_CERTACTION ) const CRYPT_CERTACTION_TYPE action,
398 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
399 int caIssueCertComplete( INOUT DBMS_INFO *dbmsInfo,
400  IN_HANDLE const CRYPT_CERTIFICATE iCertificate,
401  IN_ENUM( CRYPT_CERTACTION ) \
402  const CRYPT_CERTACTION_TYPE action,
404 
405 /* Prototypes for routines in ca_rev.c */
406 
407 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
408 int revokeCertDirect( INOUT DBMS_INFO *dbmsInfo,
409  IN_HANDLE const CRYPT_CERTIFICATE iCertificate,
410  IN_ENUM( CRYPT_CERTACTION ) \
411  const CRYPT_CERTACTION_TYPE action,
413 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 5 ) ) \
414 int caRevokeCert( INOUT DBMS_INFO *dbmsInfo,
415  IN_HANDLE const CRYPT_CERTIFICATE iCertRequest,
416  IN_HANDLE_OPT const CRYPT_CERTIFICATE iCertificate,
417  IN_ENUM( CRYPT_CERTACTION ) const CRYPT_CERTACTION_TYPE action,
419 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
420 int caIssueCRL( INOUT DBMS_INFO *dbmsInfo,
422  IN_HANDLE const CRYPT_CONTEXT caKey,
424 
425 /* Prototypes for routines in ca_misc.c */
426 
427 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
428 int updateCertLog( INOUT DBMS_INFO *dbmsInfo,
429  IN_ENUM( CRYPT_CERTACTION ) const CRYPT_CERTACTION_TYPE action,
430  IN_BUFFER_OPT( certIDlength ) const char *certID,
432  IN_BUFFER_OPT( reqCertIDlength ) const char *reqCertID,
434  IN_BUFFER_OPT( subjCertIDlength ) const char *subjCertID,
436  IN_BUFFER_OPT( dataLength ) const void *data,
438  IN_ENUM( DBMS_UPDATE ) const DBMS_UPDATE_TYPE updateType );
439 RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
440 int updateCertErrorLog( INOUT DBMS_INFO *dbmsInfo,
442  IN_STRING const char *errorString,
443  IN_BUFFER_OPT( certIDlength ) const char *certID,
444  IN_LENGTH_SHORT_Z const int certIDlength,
445  IN_BUFFER_OPT( reqCertIDlength ) const char *reqCertID,
446  IN_LENGTH_SHORT_Z const int reqCertIDlength,
447  IN_BUFFER_OPT( subjCertIDlength ) const char *subjCertID,
448  IN_LENGTH_SHORT_Z const int subjCertIDlength,
449  IN_BUFFER_OPT( dataLength ) const void *data,
450  IN_LENGTH_SHORT_Z const int dataLength );
451 RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
452 int updateCertErrorLogMsg( INOUT DBMS_INFO *dbmsInfo,
453  IN_ERROR const int errorStatus,
454  IN_STRING const char *errorString );
455 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 5 ) ) \
456 int caGetIssuingUser( INOUT DBMS_INFO *dbmsInfo,
458  IN_BUFFER( initialCertIDlength ) const char *initialCertID,
460  const int initialCertIDlength,
463 int initDBMSCA( INOUT KEYSET_INFO *keysetInfoPtr );