#include "csdatabase.h"
#include "detachedrep.h"
namespace Security {
namespace CodeSigning {
using namespace SQLite;
ModuleNexus<SignatureDatabase> signatureDatabase;
ModuleNexus<SignatureDatabaseWriter> signatureDatabaseWriter;
const char SignatureDatabase::defaultPath[] = "/var/db/DetachedSignatures";
const char schema[] = "\
create table if not exists code ( \n\
id integer primary key on conflict replace autoincrement not null, \n\
global integer null references global (id), \n\
identifier text not null, \n\
architecture integer, \n\
identification blob not null unique on conflict replace, \n\
signature blob not null, \n\
created text default current_timestamp \n\
); \n\
create index if not exists identifier_index on code (identifier); \n\
create index if not exists architecture_index on code (architecture); \n\
create index if not exists id_index on code (identification); \n\
\n\
create table if not exists global ( \n\
id integer primary key on conflict replace autoincrement not null, \n\
sign_location text not null, \n\
signature blob null \n\
); \n\
create index if not exists location_index on global (sign_location); \n\
";
SignatureDatabase::SignatureDatabase(const char *path, int flags)
: SQLite::Database(path, flags, true) {
}
SignatureDatabase::~SignatureDatabase()
{ }
FilterRep *SignatureDatabase::findCode(DiskRep *rep)
{
if (CFRef<CFDataRef> identification = rep->identification())
if (!this->empty()) {
SQLite::Statement query(*this,
"select code.signature, global.signature from code, global \
where code.identification = ?1 and code.global = global.id;");
query.bind(1) = identification.get();
if (query.nextRow()) {
CFRef<CFDataRef> sig = query[0].data();
CFRef<CFDataRef> gsig = query[1].data();
return new DetachedRep(sig, gsig, rep, "system");
}
}
return NULL;
}
void SignatureDatabaseWriter::storeCode(const BlobCore *sig, const char *location)
{
if (!this->isOpen()) MacOSError::throwMe(errSecCSDBAccess);
Transaction xa(*this, Transaction::exclusive); if (this->empty())
this->execute(schema); if (const EmbeddedSignatureBlob *esig = EmbeddedSignatureBlob::specific(sig)) { int64 globid = insertGlobal(location, NULL);
insertCode(globid, 0, esig);
xa.commit();
return;
} else if (const DetachedSignatureBlob *dsblob = DetachedSignatureBlob::specific(sig)) {
int64 globid = insertGlobal(location, dsblob->find(0));
unsigned count = dsblob->count();
for (unsigned n = 0; n < count; n++)
if (uint32_t arch = dsblob->type(n))
insertCode(globid, arch, EmbeddedSignatureBlob::specific(dsblob->blob(n)));
xa.commit();
return;
}
MacOSError::throwMe(errSecCSSignatureInvalid);
}
int64 SignatureDatabaseWriter::insertGlobal(const char *location, const BlobCore *blob)
{
Statement insert(*this, "insert into global (sign_location, signature) values (?1, ?2);");
insert.bind(1) = location;
if (blob)
insert.bind(2).blob(blob, blob->length(), true);
insert();
return lastInsert();
}
void SignatureDatabaseWriter::insertCode(int64 globid, int arch, const EmbeddedSignatureBlob *sig)
{
const BlobWrapper *ident = BlobWrapper::specific(sig->find(cdIdentificationSlot));
assert(ident);
const CodeDirectory *cd = CodeDirectory::specific(sig->find(cdCodeDirectorySlot));
assert(cd);
Statement insert(*this,
"insert into code (global, identifier, architecture, identification, signature) values (?1, ?2, ?3, ?4, ?5);");
insert.bind(1) = globid;
insert.bind(2) = cd->identifier();
if (arch)
insert.bind(3) = arch;
insert.bind(4).blob(ident->data(), ident->length(), true);
insert.bind(5).blob(sig, sig->length(), true);
insert();
}
} }