mirror of
https://github.com/berkeleydb/libdb.git
synced 2024-09-29 11:36:56 +00:00
350 lines
8.5 KiB
C
350 lines
8.5 KiB
C
/*
|
|
* See the file LICENSE for redistribution information.
|
|
*
|
|
* Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
|
|
*
|
|
* $Id$
|
|
*
|
|
* A c unit test program for encrypting a database. [#19539].
|
|
*
|
|
* There are two ways to encrypt a database:
|
|
* i) If the database is attached to an opened environment, use
|
|
* DB_ENV->set_encrypt() and DB->set_flags();
|
|
* ii) Otherwise, use DB->set_encrypt().
|
|
*
|
|
* Note:
|
|
* 1) DB->set_encrypt() cannot used in an opened environment,
|
|
* no matter whether this environment is encrypted or not.
|
|
* 2) Single DB_ENV->set_encrypt() is not enough to encrypt a database
|
|
* inside an encrypted environment, DB->set_flag should also be applied to
|
|
* this specific database.
|
|
* 3) DB->set_flag() should only be called in an encrypted environment.
|
|
*/
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <time.h>
|
|
|
|
#include "db.h"
|
|
#include "CuTest.h"
|
|
|
|
const char *progname_crypt = "encryption";
|
|
#define DATABASE "encryption.db"
|
|
#define PASSWORD "ENCRYPT_KEY"
|
|
|
|
typedef struct crypt_config {
|
|
int in_env;
|
|
int is_env_encrypt;
|
|
int is_db_encrypt;
|
|
int is_db_flags_encrypt;
|
|
} CRYPT_CONFIG;
|
|
|
|
int closeDb __P((DB_ENV *, DB *));
|
|
int dbPutGet __P((CuTest *, DB *));
|
|
int encryptTestCase __P((CuTest *, int, int, int, int));
|
|
int initConfig __P((CRYPT_CONFIG *, int, int, int, int));
|
|
int openDb __P((CuTest *, DB **dbp, DB_ENV *, char *, CRYPT_CONFIG *));
|
|
int openEnv __P((CuTest *, DB_ENV **, char *, int));
|
|
int reOpen __P((CuTest *, DB **, char *, CRYPT_CONFIG *));
|
|
|
|
int TestNoEncryptedDb(CuTest *ct) {
|
|
CuAssert(ct, "TestNoEncryption", encryptTestCase(ct, 0, 0, 0, 0) == 0);
|
|
return (0);
|
|
}
|
|
|
|
int TestEncryptedDbFlag(CuTest *ct) {
|
|
CuAssert(ct, "TestEncryptedDbFlag",
|
|
encryptTestCase(ct, 0, 0, 0, 1) == 0);
|
|
return (0);
|
|
}
|
|
|
|
int TestEncryptedDb(CuTest *ct) {
|
|
CuAssert(ct, "TestEncryptedDb", encryptTestCase(ct, 0, 0, 1, 0) == 0);
|
|
return (0);
|
|
}
|
|
|
|
int TestEncryptedDbFlagAndDb(CuTest *ct) {
|
|
CuAssert(ct, "TestEncryptedDbFlagAndDb",
|
|
encryptTestCase(ct, 0, 0, 1, 1) == 0);
|
|
return (0);
|
|
}
|
|
|
|
int TestEnvWithNoEncryption(CuTest *ct) {
|
|
CuAssert(ct, "TestEnvWithNoEncryption",
|
|
encryptTestCase(ct, 1, 0, 0, 0) == 0);
|
|
return (0);
|
|
}
|
|
|
|
int TestEnvWithEncryptedDbFlag(CuTest *ct) {
|
|
CuAssert(ct, "TestEnvWithEncryptedDbFlag",
|
|
encryptTestCase(ct, 1, 0, 0, 1) == 0);
|
|
return (0);
|
|
}
|
|
|
|
int TestEnvWithEncryptedDb(CuTest *ct) {
|
|
CuAssert(ct, "TestEnvWithEncryptedDb",
|
|
encryptTestCase(ct, 1, 0, 1, 0) == 0);
|
|
return (0);
|
|
}
|
|
|
|
int TestEnvWithEncryptedDbFlagAndDb(CuTest *ct) {
|
|
CuAssert(ct, "TestEnvWithEncryptedDbFlagAndDb",
|
|
encryptTestCase(ct, 1, 0, 1, 1) == 0);
|
|
return (0);
|
|
}
|
|
|
|
int TestEncyptedEnv(CuTest *ct) {
|
|
CuAssert(ct, "TestEncyptedEnv", encryptTestCase(ct, 1, 1, 0, 0) == 0);
|
|
return (0);
|
|
}
|
|
|
|
int TestEncyptedEnvWithEncyptedDbFlag(CuTest *ct) {
|
|
CuAssert(ct, "TestEncyptedEnvWithEncyptedDbFlag",
|
|
encryptTestCase(ct, 1, 1, 0, 1) == 0);
|
|
return (0);
|
|
}
|
|
|
|
int TestEncyptedEnvWithEncyptedDb(CuTest *ct) {
|
|
CuAssert(ct, "TestEncyptedEnvWithEncyptedDb",
|
|
encryptTestCase(ct, 1, 1, 1, 0) == 0);
|
|
return (0);
|
|
}
|
|
|
|
int TestEncyptedEnvWithEncryptedDbFlagAndDb(CuTest *ct) {
|
|
CuAssert(ct, "TestEncyptedEnvWithEncryptedDbFlagAndDb",
|
|
encryptTestCase(ct, 1, 1, 1, 1) == 0);
|
|
return (0);
|
|
}
|
|
|
|
int initConfig(CRYPT_CONFIG *crypt, int in_env, int is_env_encrypt,
|
|
int is_db_encrypt, int is_db_flags_encrypt)
|
|
{
|
|
memset(crypt, 0, sizeof(CRYPT_CONFIG));
|
|
crypt->in_env = in_env;
|
|
crypt->is_env_encrypt = is_env_encrypt;
|
|
crypt->is_db_encrypt = is_db_encrypt;
|
|
crypt->is_db_flags_encrypt = is_db_flags_encrypt;
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* in_env: whether open the database in an environment
|
|
* is_env_encrypt: whether call DB_ENV->set_encrypt() with DB_ENCRYPT_AES
|
|
* is_db_encrypt: whether call DB->set_encrypt() with DB_ENCRYPT_AES
|
|
* is_db_flags_encrypt: whether call DB->set_flags() with DB_ENCRYPT
|
|
*/
|
|
int encryptTestCase(CuTest *ct, int in_env, int is_env_encrypt,
|
|
int is_db_encrypt, int is_db_flags_encrypt)
|
|
{
|
|
CRYPT_CONFIG crypt;
|
|
DB_ENV *dbenv;
|
|
DB *dbp;
|
|
char dbname[100], *home;
|
|
int ret;
|
|
|
|
dbenv = NULL;
|
|
dbp = NULL;
|
|
home = "TESTDIR";
|
|
ret = 0;
|
|
|
|
TestEnvConfigTestSetup(ct);
|
|
initConfig(&crypt, in_env, is_env_encrypt, is_db_encrypt,
|
|
is_db_flags_encrypt);
|
|
|
|
if (in_env) {
|
|
strcpy(dbname, DATABASE);
|
|
CuAssert(ct, "Open environment",
|
|
openEnv(ct, &dbenv, home, is_env_encrypt) == 0);
|
|
} else
|
|
sprintf(dbname, ".//%s//%s", home, DATABASE);
|
|
|
|
ret = openDb(ct, &dbp, dbenv, dbname, &crypt);
|
|
|
|
/* Close the dbenv, dbp handle.*/
|
|
CuAssert(ct, "closeDb", closeDb(dbenv, dbp) == 0);
|
|
dbenv = NULL;
|
|
dbp = NULL;
|
|
|
|
/* Re-open the database and do some operations. */
|
|
if (!ret) {
|
|
sprintf(dbname, ".//%s//%s", home, DATABASE);
|
|
CuAssert(ct, "Re-open database",
|
|
reOpen(ct, &dbp, dbname, &crypt) == 0);
|
|
|
|
/* Close the dbenv, dbp handle. */
|
|
CuAssert(ct, "closeDb", closeDb(dbenv, dbp) == 0);
|
|
dbenv = NULL;
|
|
dbp = NULL;
|
|
}
|
|
|
|
TestEnvConfigTestTeardown(ct);
|
|
|
|
return (0);
|
|
}
|
|
|
|
int openEnv(CuTest *ct, DB_ENV **dbenvp, char *home, int is_encrypt)
|
|
{
|
|
DB_ENV *dbenv;
|
|
|
|
dbenv = NULL;
|
|
|
|
CuAssert(ct, "db_env_create", db_env_create(&dbenv, 0) == 0);
|
|
|
|
*dbenvp = dbenv;
|
|
|
|
dbenv->set_errcall(dbenv, NULL);
|
|
|
|
if (is_encrypt)
|
|
CuAssert(ct, "DB_ENV->set_encrypt:DB_ENCRYPT_AES",
|
|
dbenv->set_encrypt(dbenv, PASSWORD, DB_ENCRYPT_AES) == 0);
|
|
|
|
CuAssert(ct, "DB_ENV->open", dbenv->open(dbenv, home,
|
|
DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE, 0) == 0);
|
|
|
|
return (0);
|
|
}
|
|
|
|
int openDb(CuTest *ct, DB **dbpp, DB_ENV *dbenv, char *dbname,
|
|
CRYPT_CONFIG *crypt)
|
|
{
|
|
DB *dbp;
|
|
int expected_value, ret;
|
|
|
|
dbp = NULL;
|
|
ret = 0;
|
|
|
|
CuAssert(ct, "openDb:db_create:%s", db_create(&dbp, dbenv, 0) == 0);
|
|
|
|
*dbpp = dbp;
|
|
|
|
dbp->set_errcall(dbp, NULL);
|
|
|
|
/*
|
|
* DB->set_flag() with DB_ENCRYPT should only be used in
|
|
* an encrypted environment.
|
|
*/
|
|
if (crypt->is_db_flags_encrypt) {
|
|
ret = dbp->set_flags(dbp, DB_ENCRYPT);
|
|
|
|
if (!crypt->in_env || !crypt->is_env_encrypt)
|
|
expected_value = EINVAL;
|
|
else
|
|
expected_value = 0;
|
|
|
|
CuAssert(ct, "openDb:DB->set_flags:DB_ENCRYPT",
|
|
ret == expected_value);
|
|
}
|
|
|
|
/* DB->set_encrypt() cannot be used in an opened environment. */
|
|
if (!ret && crypt->is_db_encrypt) {
|
|
ret = dbp->set_encrypt(dbp, PASSWORD, DB_ENCRYPT_AES);
|
|
|
|
if (crypt->in_env)
|
|
expected_value = EINVAL;
|
|
else
|
|
expected_value = 0;
|
|
|
|
CuAssert(ct, "openDb:DB->set_encrypt:DB_ENCRYPT_AES",
|
|
ret == expected_value);
|
|
}
|
|
|
|
if (!ret) {
|
|
CuAssert(ct, "openDb: DB->open", dbp->open(dbp, NULL,
|
|
dbname, NULL, DB_BTREE, DB_CREATE, 0) == 0);
|
|
CuAssert(ct, "dbPutGet", dbPutGet(ct, dbp) == 0);
|
|
}
|
|
|
|
return (ret);
|
|
}
|
|
|
|
/* Re-open the previous database and check the encryption. */
|
|
int reOpen(CuTest *ct, DB **dbpp, char *dbname, CRYPT_CONFIG *crypt)
|
|
{
|
|
DB *dbp;
|
|
int expected_value, ret;
|
|
|
|
dbp = NULL;
|
|
expected_value = ret = 0;
|
|
|
|
CuAssert(ct, "reOpen: db_create fails",
|
|
db_create(&dbp, NULL, 0) == 0);
|
|
|
|
*dbpp = dbp;
|
|
|
|
dbp->set_errcall(dbp, NULL);
|
|
|
|
/* Re-open a database should fail if the database is encrypted.*/
|
|
ret = dbp->open(dbp, NULL, dbname, NULL, DB_UNKNOWN, 0, 0);
|
|
|
|
/*
|
|
* If call DB_ENV->set_encrypt and DB->set_flag with DB_ENCRYPT,
|
|
* the database should be successfully encrypted, hence, re-open
|
|
* should be fail.
|
|
*
|
|
* Or
|
|
*
|
|
* If call DB->set_encrypt without in an environment,
|
|
* then the database can be successfully encrypted, hence,
|
|
* re-open should fails and return error code EINVAL.
|
|
*/
|
|
if ((crypt->in_env && crypt->is_env_encrypt &&
|
|
crypt->is_db_flags_encrypt) ||
|
|
(crypt->is_db_encrypt && !crypt->in_env))
|
|
expected_value = EINVAL;
|
|
|
|
CuAssert(ct, "reOpen: DB->open", ret == expected_value);
|
|
|
|
/* Do some put and get operations if re-open is successful. */
|
|
if (!ret)
|
|
CuAssert(ct, "dbPutGet", dbPutGet(ct, dbp) == 0);
|
|
|
|
return (0);
|
|
}
|
|
|
|
int dbPutGet(CuTest *ct, DB *dbp)
|
|
{
|
|
DBT key, data;
|
|
char buf[1024];
|
|
const char *str = "abcdefghijklmnopqrst";
|
|
int cnt, ret;
|
|
size_t len;
|
|
|
|
ret = 0;
|
|
|
|
memset(&key, 0, sizeof(DBT));
|
|
memset(&data, 0, sizeof(DBT));
|
|
|
|
srand((int)time(NULL));
|
|
|
|
for (cnt = 1; cnt < 10001; cnt++) {
|
|
len = rand() % strlen(str) + 1;
|
|
(void)sprintf(buf, "%05d_%*s", cnt, len, str);
|
|
|
|
key.data = &cnt;
|
|
key.size = sizeof(cnt);
|
|
|
|
data.data = buf;
|
|
data.size = (u_int32_t)strlen(buf) + 1;
|
|
|
|
CuAssert(ct, "DB->put",
|
|
dbp->put(dbp, NULL, &key, &data, 0) == 0);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
int closeDb(DB_ENV *dbenv, DB *dbp)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (dbp != NULL && (ret = dbp->close(dbp, 0)) != 0)
|
|
fprintf(stderr, "%s: DB->close: %s",
|
|
progname_crypt, db_strerror(ret));
|
|
|
|
if (dbenv != NULL && (ret = dbenv->close(dbenv, 0)) != 0)
|
|
fprintf(stderr, "%s: DB_ENV->close: %s",
|
|
progname_crypt, db_strerror(ret));
|
|
|
|
return (ret);
|
|
}
|