]> git.saurik.com Git - apple/libsecurity_codesigning.git/blob - lib/csdatabase.cpp
76912ced78be0186c76063e9500cd569d3e3339a
[apple/libsecurity_codesigning.git] / lib / csdatabase.cpp
1 /*
2 * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 //
25 // csdb - system-supported Code Signing related database interfaces
26 //
27 #include "csdatabase.h"
28 #include "detachedrep.h"
29
30 namespace Security {
31 namespace CodeSigning {
32
33 using namespace SQLite;
34
35
36 //
37 // The one and only SignatureDatabase object.
38 // It auto-adapts to readonly vs. writable use.
39 //
40 ModuleNexus<SignatureDatabase> signatureDatabase;
41
42
43 //
44 // Default path to the signature database.
45 //
46 const char SignatureDatabase::defaultPath[] = "/var/db/DetachedSignatures";
47
48
49 //
50 // Creation commands to initialize the system database.
51 //
52 const char schema[] = "\
53 create table if not exists code ( \n\
54 id integer primary key on conflict replace autoincrement not null, \n\
55 global integer null references global (id), \n\
56 identifier text not null, \n\
57 architecture integer, \n\
58 identification blob not null unique on conflict replace, \n\
59 signature blob not null, \n\
60 created text default current_timestamp \n\
61 ); \n\
62 create index if not exists identifier_index on code (identifier); \n\
63 create index if not exists architecture_index on code (architecture); \n\
64 create index if not exists id_index on code (identification); \n\
65 \n\
66 create table if not exists global ( \n\
67 id integer primary key on conflict replace autoincrement not null, \n\
68 sign_location text not null, \n\
69 signature blob null \n\
70 ); \n\
71 create index if not exists location_index on global (sign_location); \n\
72 ";
73
74
75
76 //
77 // Open the database (creating it if necessary and possible).
78 // Note that this isn't creating the schema; we do that on first write.
79 //
80 SignatureDatabase::SignatureDatabase(const char *path, int flags)
81 : SQLite::Database(path, flags)
82 {
83 }
84
85 SignatureDatabase::~SignatureDatabase()
86 { /* virtual */ }
87
88
89 //
90 // Consult the database to find code by identification blob.
91 // Return the signature and (optional) global data blobs.
92 //
93 FilterRep *SignatureDatabase::findCode(DiskRep *rep)
94 {
95 if (CFRef<CFDataRef> identification = rep->identification())
96 if (!this->empty()) {
97 SQLite::Statement query(*this,
98 "select code.signature, global.signature from code, global \
99 where code.identification = ?1 and code.global = global.id;");
100 query.bind(1) = identification.get();
101 if (query.nextRow())
102 return new DetachedRep(query[0].data(), query[1].data(), rep, "system");
103 }
104
105 // no joy
106 return NULL;
107 }
108
109
110 //
111 // Given a unified detached signature blob, store its data in the database.
112 // This writes exactly one Global record, plus one Code record per architecture
113 // (where non-architectural code is treated as single-architecture).
114 //
115 void SignatureDatabase::storeCode(const BlobCore *sig, const char *location)
116 {
117 Transaction xa(*this, Transaction::exclusive); // lock out everyone
118 if (this->empty())
119 this->execute(schema); // initialize schema
120 if (const EmbeddedSignatureBlob *esig = EmbeddedSignatureBlob::specific(sig)) { // architecture-less
121 int64 globid = insertGlobal(location, NULL);
122 insertCode(globid, 0, esig);
123 xa.commit();
124 return;
125 } else if (const DetachedSignatureBlob *dsblob = DetachedSignatureBlob::specific(sig)) {
126 int64 globid = insertGlobal(location, dsblob->find(0));
127 unsigned count = dsblob->count();
128 for (unsigned n = 0; n < count; n++)
129 if (uint32_t arch = dsblob->type(n))
130 insertCode(globid, arch, EmbeddedSignatureBlob::specific(dsblob->blob(n)));
131 xa.commit();
132 return;
133 }
134
135 MacOSError::throwMe(errSecCSSignatureInvalid);
136
137 }
138
139 int64 SignatureDatabase::insertGlobal(const char *location, const BlobCore *blob)
140 {
141 Statement insert(*this, "insert into global (sign_location, signature) values (?1, ?2);");
142 insert.bind(1) = location;
143 if (blob)
144 insert.bind(2).blob(blob, blob->length(), true);
145 insert();
146 return lastInsert();
147 }
148
149 void SignatureDatabase::insertCode(int64 globid, int arch, const EmbeddedSignatureBlob *sig)
150 {
151 // retrieve binary identifier (was added by signer)
152 const BlobWrapper *ident = BlobWrapper::specific(sig->find(cdIdentificationSlot));
153 assert(ident);
154
155 // extract CodeDirectory to get some information from it
156 const CodeDirectory *cd = CodeDirectory::specific(sig->find(cdCodeDirectorySlot));
157 assert(cd);
158
159 // write the record
160 Statement insert(*this,
161 "insert into code (global, identifier, architecture, identification, signature) values (?1, ?2, ?3, ?4, ?5);");
162 insert.bind(1) = globid;
163 insert.bind(2) = cd->identifier();
164 if (arch)
165 insert.bind(3) = arch;
166 insert.bind(4).blob(ident->data(), ident->length(), true);
167 insert.bind(5).blob(sig, sig->length(), true);
168 insert();
169 }
170
171
172
173 } // end namespace CodeSigning
174 } // end namespace Security