From c45562762aab7e874eac71792f9eebb5185ee47d Mon Sep 17 00:00:00 2001 From: Rob Austein Date: Wed, 1 Jul 2015 16:30:51 -0400 Subject: Add p11util program to do things like fiddling with the BPKDF2 iteration count, setting PINs, and so forth. Factor some SQL utility code out to a separate file so we can reuse it for p11util. --- sql_common.h | 255 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 sql_common.h (limited to 'sql_common.h') diff --git a/sql_common.h b/sql_common.h new file mode 100644 index 0000000..8f1844b --- /dev/null +++ b/sql_common.h @@ -0,0 +1,255 @@ +/* + * sql_common.h + * ------------ + * + * Common definitions and SQL support code for Cryptech PKCS #11 engine. + * + * We could split the functions out of this into a separate .c file, + * but there's no real point in doing so, and it's simpler to keep it + * all in one file, the build process is complex enough already. + * + * Author: Rob Austein + * Copyright (c) 2015, SUNET + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SQL_COMMON_H_ +#define _SQL_COMMON_H_ + +#include +#include +#include +#include +#include + +#include + +/* + * Placeholders for PIN length limits. Figure out real values later. + */ + +#warning Figure out PIN length limits +#define P11_MIN_PIN_LENGTH 16 +#define P11_MAX_PIN_LENGTH 4096 + +/* + * Debugging control. + */ + +#ifndef DEBUG_SQL +#define DEBUG_SQL 1 +#endif + +/* + * Default filename for SQL database lives. Can be overriden at + * runtime by setting PKCS11_DATABASE environment variable. + */ + +#ifndef SQL_DATABASE +#define SQL_DATABASE ".cryptech-pkcs11.db" +#endif + +/* + * SQL database. + */ + +static sqlite3 *sqldb = NULL; + +/* + * Error checking for SQLite calls. + */ + +#if DEBUG_SQL + +#define sql_whine(_expr_) \ + (fprintf(stderr, "%s:%u: %s returned %s\n", \ + __FILE__, __LINE__, #_expr_, sqlite3_errmsg(sqldb)), \ + sql_breakpoint()) + +#else /* DEBUG_SQL */ + +#define sql_whine(_expr_) \ + ((void) 0) + +#endif /* DEBUG_SQL */ + +#define sql_check(_good_, _expr_) \ + ((_expr_) == (_good_) ? 1 : (sql_whine(_expr_), 0)) + +#define sql_check_ok(_expr_) sql_check(SQLITE_OK, _expr_) +#define sql_check_row(_expr_) sql_check(SQLITE_ROW, _expr_) +#define sql_check_done(_expr_) sql_check(SQLITE_DONE, _expr_) +#define sql_whine_step() sql_whine(sqlite3_step()) + +/* + * Hook on which to hang a debugger breakpoint on SQL errors. + */ + +#if DEBUG_SQL +static void sql_breakpoint(void) +{ + fprintf(stderr, "[sql_breakpoint]\n"); +} +#endif + +/* + * Execute SQL code that doesn't require a prepared query. + */ + +static int sql_exec(const char *cmd) +{ + char *msg = NULL; + + if (sql_check_ok(sqlite3_exec(sqldb, cmd, NULL, NULL, &msg))) + return 1; + +#if DEBUG_SQL + if (msg != NULL) + fprintf(stderr, "[%s]\n", msg); +#endif + + return 0; +} + +/* + * Initialize SQL. This includes loading our schema, portions of + * which live in the temp (memory) database thus always need to be + * created on startup. + */ + +static int sql_init(void) +{ + static const char schema[] = +#include "schema.h" + ; + + assert(sqldb == NULL); + + const char * const env = getenv("PKCS11_DATABASE"); + const char * const home = getenv("HOME"); + const char * const base = SQL_DATABASE; + int ok; + + if (env != NULL) { + ok = sql_check_ok(sqlite3_open(env, &sqldb)); + } + + else if (home == NULL) { + ok = sql_check_ok(sqlite3_open(base, &sqldb)); + } + + else { + char fn[strlen(home) + strlen(base) + 2]; + snprintf(fn, sizeof(fn), "%s/%s", home, base); + ok = sql_check_ok(sqlite3_open(fn, &sqldb)); + } + + return ok && sql_exec(schema); +} + +/* + * Shut down SQL. + * + * Yes, this can return failure, although it's not clear what we're + * meant to do about that if the application is going to shut down + * regardless of what we do. I guess we could loop retrying a few + * times for errors like SQLITE_BUSY, but that's about it. + */ + +static int sql_fini(void) +{ + if (!sql_check_ok(sqlite3_close(sqldb))) + return 0; + + sqldb = NULL; + return 1; +} + +/* + * GCC attribute declaration to help catch format string errors, + * ignored by other compilers. + */ + +#ifdef __GNUC__ +static int sql_prepare(sqlite3_stmt **q, + const char *format, ...) + __attribute__ ((format (printf, 2, 3))); +#endif + +/* + * Prepare an SQLite3 query, using vsnprintf() to format the query. + * + * WARNING WARNING WARNING WARNING + * + * Do not use this formatting mechanism for anything involving + * user-supplied data. It's only intended to handle things like + * selecting between two parallel table structures or queries using + * manifest constants that are only available in C header files. + */ + +static int sql_prepare(sqlite3_stmt **q, const char *format, ...) +{ + char buffer[2048]; + va_list ap; + size_t n; + + va_start(ap, format); + n = vsnprintf(buffer, sizeof(buffer), format, ap); + va_end(ap); + + if (n >= sizeof(buffer)) + return SQLITE_TOOBIG; + + return sqlite3_prepare_v2(sqldb, buffer, -1, q, NULL); +} + +/* + * This idiom occurs frequently, bundle it so we have the option of + * doing it along with the normal conditional control flow that SQL + * queries seem to follow. + */ + +static int sql_finalize_and_clear(sqlite3_stmt **q) +{ + assert(q != NULL); + + int err = sqlite3_finalize(*q); + + if (err != SQLITE_OK) + return err; + + *q = NULL; + return SQLITE_OK; +} + +#endif /* _SQL_COMMON_H_ */ + +/* + * Local variables: + * indent-tabs-mode: nil + * End: + */ -- cgit v1.2.3