#include "testclient.h"
#include "testutils.h"
void blobs()
{
printf("* Database blob encryption test\n");
ClientSession ss(CssmAllocator::standard(), CssmAllocator::standard());
DbTester db1(ss, "/tmp/one", NULL, 60, true);
DbTester db2(ss, "/tmp/two", NULL, 30, false);
CssmData dbBlob;
ss.encodeDb(db1, dbBlob);
DbHandle db1a = ss.decodeDb(db1.dbId, &nullCred, dbBlob);
ss.releaseDb(db1);
if (db1 == db1a)
detail("REUSED DB HANDLE ON DECODEDB (probably wrong)");
DBParameters savedParams;
ss.getDbParameters(db1a, savedParams);
assert(savedParams.idleTimeout == db1.params.idleTimeout);
assert(savedParams.lockOnSleep == db1.params.lockOnSleep);
detail("Database encode/decode passed");
try {
ss.getDbParameters(db1, savedParams);
printf("OLD DATABASE HANDLE NOT PURGED (possibly wrong)\n");
} catch (const CssmCommonError &err) {
detail(err, "old DB handle rejected");
}
DbHandle db1b = ss.decodeDb(db1.dbId, &nullCred, dbBlob);
ss.releaseDb(db1a);
ss.releaseDb(db1b);
ss.releaseDb(db2);
}
void databases()
{
printf("* Database manipulation test\n");
CssmAllocator &alloc = CssmAllocator::standard();
ClientSession ss(alloc, alloc);
AutoCredentials pwCred(alloc);
StringData passphrase("two");
StringData badPassphrase("three");
pwCred += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK,
new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
new(alloc) ListElement(passphrase));
pwCred += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
new(alloc) ListElement(badPassphrase));
DbTester db1(ss, "/tmp/one", NULL, 30, true);
DbTester db2(ss, "/tmp/two", &pwCred, 60, false);
CssmData dbBlob;
ss.encodeDb(db1, dbBlob);
DbHandle db1b = ss.decodeDb(db1.dbId, &nullCred, dbBlob);
if (db1b == db1.dbRef)
detail("REUSED DB HANDLE ON DECODEDB (probably wrong)");
DbHandle db1c = ss.decodeDb(db1.dbId, &nullCred, dbBlob);
ss.lock(db1);
ss.lock(db2);
prompt("unlock");
ss.unlock(db1);
prompt();
ss.unlock(db1b); ss.lock(db1c); prompt("unlock");
ss.unlock(db1); prompt();
db2.unlock("wrong passphrase"); AutoCredentials pwCred2(alloc);
pwCred2 += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
new(alloc) ListElement(passphrase));
ss.authenticateDb(db2, CSSM_DB_ACCESS_WRITE, &pwCred2); db2.unlock();
ss.lock(db2);
ss.lock(db2);
pwCred2 += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK,
new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
new(alloc) ListElement(badPassphrase));
db2.changePassphrase(&pwCred2);
CssmData blob2;
ss.encodeDb(db2, blob2);
DbHandle db2a = ss.decodeDb(db2.dbId, &pwCred, blob2);
db2.unlock("old passphrase accepted");
ss.lock(db2a);
ss.unlock(db2a);
detail("New passphrase accepted");
ss.authenticateDb(db2, CSSM_DB_ACCESS_WRITE, NULL);
prompt("cancel");
db2.unlock("null credential accepted");
prompt();
StringData newPassphrase("hollerith");
AutoCredentials pwCred3(alloc);
pwCred3 += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK,
new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
new(alloc) ListElement(newPassphrase));
pwCred3 += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
new(alloc) ListElement(passphrase));
db2.changePassphrase(&pwCred3, "accepting original (unchanged) passphrase");
AutoCredentials pwCred4(alloc);
pwCred4 += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK,
new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
new(alloc) ListElement(newPassphrase));
pwCred4 += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
new(alloc) ListElement(badPassphrase));
db2.changePassphrase(&pwCred4);
AutoCredentials pwCred5(alloc);
pwCred5 += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
new(alloc) ListElement(newPassphrase));
ss.authenticateDb(db2, CSSM_DB_ACCESS_WRITE, &pwCred5);
db2.unlock();
detail("Final passphrase change verified");
}
void keyBlobs()
{
printf("* Keyblob encryption test\n");
CssmAllocator &alloc = CssmAllocator::standard();
ClientSession ss(alloc, alloc);
DLDbIdentifier dbId1(ssuid, "/tmp/one", NULL);
DBParameters initialParams1 = { 3600, false };
DbHandle db = ss.createDb(dbId1, NULL, NULL, initialParams1);
detail("Database created");
StringData theAclPassword("Strenge Geheimsache");
AclEntryPrototype initialAcl;
initialAcl.TypedSubject = TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_PASSWORD,
new(alloc) ListElement(theAclPassword));
AclEntryInput initialAclInput(initialAcl);
AutoCredentials cred(alloc);
cred += TypedList(alloc, CSSM_SAMPLE_TYPE_PASSWORD,
new(alloc) ListElement(theAclPassword));
const CssmCryptoData seed(StringData("Farmers' day"));
FakeContext genContext(CSSM_ALGCLASS_KEYGEN, CSSM_ALGID_DES,
&::Context::Attr(CSSM_ATTRIBUTE_KEY_LENGTH, 64),
&::Context::Attr(CSSM_ATTRIBUTE_SEED, seed),
NULL);
KeyHandle key;
CssmKey::Header header;
ss.generateKey(db, genContext, CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT,
NULL, &initialAclInput, key, header);
detail("Key generated");
StringData clearText("Yet another boring cleartext sample string text sequence.");
StringData iv("Aardvark");
CssmKey nullKey; memset(&nullKey, 0, sizeof(nullKey));
FakeContext cryptoContext(CSSM_ALGCLASS_SYMMETRIC, CSSM_ALGID_DES,
&::Context::Attr(CSSM_ATTRIBUTE_KEY, nullKey),
&::Context::Attr(CSSM_ATTRIBUTE_INIT_VECTOR, iv),
&::Context::Attr(CSSM_ATTRIBUTE_MODE, CSSM_ALGMODE_CBC_IV8),
&::Context::Attr(CSSM_ATTRIBUTE_PADDING, CSSM_PADDING_PKCS1),
&::Context::Attr(CSSM_ATTRIBUTE_ACCESS_CREDENTIALS, cred),
NULL);
CssmData cipherText;
ss.encrypt(cryptoContext, key, clearText, cipherText);
detail("Plaintext encrypted with original key");
CssmData blob;
ss.encodeKey(key, blob);
ss.releaseKey(key);
detail("Key encoded and released");
CssmKey::Header decodedHeader;
KeyHandle key2 = ss.decodeKey(db, blob, decodedHeader);
detail("Key decoded");
CssmData recovered;
ss.decrypt(cryptoContext, key2, cipherText, recovered);
assert(recovered == clearText);
detail("Decoded key correctly decrypts ciphertext");
if (!memcmp(&header, &decodedHeader, sizeof(header))) {
detail("All header fields match");
} else {
assert(header.algorithm() == decodedHeader.algorithm());
assert(header.blobType() == decodedHeader.blobType());
assert(header.blobFormat() == decodedHeader.blobFormat());
assert(header.keyClass() == decodedHeader.keyClass());
assert(header.attributes() == decodedHeader.attributes());
assert(header.usage() == decodedHeader.usage());
printf("Some header fields differ (probably okay)\n");
}
memset(&cred, 0, sizeof(cred));
try {
ss.decrypt(cryptoContext, key2, cipherText, recovered);
error("RESTORED ACL FAILS TO RESTRICT");
} catch (CssmError &err) {
detail(err, "Restored key restricts access properly");
}
}