]>
Commit | Line | Data |
---|---|---|
d1c1ab47 A |
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; | |
f60086fc | 41 | ModuleNexus<SignatureDatabaseWriter> signatureDatabaseWriter; |
d1c1ab47 A |
42 | |
43 | ||
44 | // | |
45 | // Default path to the signature database. | |
46 | // | |
47 | const char SignatureDatabase::defaultPath[] = "/var/db/DetachedSignatures"; | |
48 | ||
49 | ||
50 | // | |
51 | // Creation commands to initialize the system database. | |
52 | // | |
53 | const char schema[] = "\ | |
54 | create table if not exists code ( \n\ | |
55 | id integer primary key on conflict replace autoincrement not null, \n\ | |
56 | global integer null references global (id), \n\ | |
57 | identifier text not null, \n\ | |
58 | architecture integer, \n\ | |
59 | identification blob not null unique on conflict replace, \n\ | |
60 | signature blob not null, \n\ | |
61 | created text default current_timestamp \n\ | |
62 | ); \n\ | |
63 | create index if not exists identifier_index on code (identifier); \n\ | |
64 | create index if not exists architecture_index on code (architecture); \n\ | |
65 | create index if not exists id_index on code (identification); \n\ | |
66 | \n\ | |
67 | create table if not exists global ( \n\ | |
68 | id integer primary key on conflict replace autoincrement not null, \n\ | |
69 | sign_location text not null, \n\ | |
70 | signature blob null \n\ | |
71 | ); \n\ | |
72 | create index if not exists location_index on global (sign_location); \n\ | |
73 | "; | |
74 | ||
75 | ||
76 | ||
77 | // | |
78 | // Open the database (creating it if necessary and possible). | |
79 | // Note that this isn't creating the schema; we do that on first write. | |
80 | // | |
81 | SignatureDatabase::SignatureDatabase(const char *path, int flags) | |
82 | : SQLite::Database(path, flags) | |
83 | { | |
84 | } | |
85 | ||
86 | SignatureDatabase::~SignatureDatabase() | |
87 | { /* virtual */ } | |
88 | ||
89 | ||
90 | // | |
91 | // Consult the database to find code by identification blob. | |
92 | // Return the signature and (optional) global data blobs. | |
93 | // | |
94 | FilterRep *SignatureDatabase::findCode(DiskRep *rep) | |
95 | { | |
96 | if (CFRef<CFDataRef> identification = rep->identification()) | |
97 | if (!this->empty()) { | |
98 | SQLite::Statement query(*this, | |
99 | "select code.signature, global.signature from code, global \ | |
100 | where code.identification = ?1 and code.global = global.id;"); | |
101 | query.bind(1) = identification.get(); | |
102 | if (query.nextRow()) | |
103 | return new DetachedRep(query[0].data(), query[1].data(), rep, "system"); | |
104 | } | |
105 | ||
106 | // no joy | |
107 | return NULL; | |
108 | } | |
109 | ||
110 | ||
111 | // | |
112 | // Given a unified detached signature blob, store its data in the database. | |
113 | // This writes exactly one Global record, plus one Code record per architecture | |
114 | // (where non-architectural code is treated as single-architecture). | |
115 | // | |
f60086fc | 116 | void SignatureDatabaseWriter::storeCode(const BlobCore *sig, const char *location) |
d1c1ab47 A |
117 | { |
118 | Transaction xa(*this, Transaction::exclusive); // lock out everyone | |
119 | if (this->empty()) | |
120 | this->execute(schema); // initialize schema | |
121 | if (const EmbeddedSignatureBlob *esig = EmbeddedSignatureBlob::specific(sig)) { // architecture-less | |
122 | int64 globid = insertGlobal(location, NULL); | |
123 | insertCode(globid, 0, esig); | |
124 | xa.commit(); | |
125 | return; | |
126 | } else if (const DetachedSignatureBlob *dsblob = DetachedSignatureBlob::specific(sig)) { | |
127 | int64 globid = insertGlobal(location, dsblob->find(0)); | |
128 | unsigned count = dsblob->count(); | |
129 | for (unsigned n = 0; n < count; n++) | |
130 | if (uint32_t arch = dsblob->type(n)) | |
131 | insertCode(globid, arch, EmbeddedSignatureBlob::specific(dsblob->blob(n))); | |
132 | xa.commit(); | |
133 | return; | |
134 | } | |
135 | ||
136 | MacOSError::throwMe(errSecCSSignatureInvalid); | |
137 | ||
138 | } | |
139 | ||
f60086fc | 140 | int64 SignatureDatabaseWriter::insertGlobal(const char *location, const BlobCore *blob) |
d1c1ab47 A |
141 | { |
142 | Statement insert(*this, "insert into global (sign_location, signature) values (?1, ?2);"); | |
143 | insert.bind(1) = location; | |
144 | if (blob) | |
145 | insert.bind(2).blob(blob, blob->length(), true); | |
146 | insert(); | |
147 | return lastInsert(); | |
148 | } | |
149 | ||
f60086fc | 150 | void SignatureDatabaseWriter::insertCode(int64 globid, int arch, const EmbeddedSignatureBlob *sig) |
d1c1ab47 A |
151 | { |
152 | // retrieve binary identifier (was added by signer) | |
153 | const BlobWrapper *ident = BlobWrapper::specific(sig->find(cdIdentificationSlot)); | |
154 | assert(ident); | |
155 | ||
156 | // extract CodeDirectory to get some information from it | |
157 | const CodeDirectory *cd = CodeDirectory::specific(sig->find(cdCodeDirectorySlot)); | |
158 | assert(cd); | |
159 | ||
160 | // write the record | |
161 | Statement insert(*this, | |
162 | "insert into code (global, identifier, architecture, identification, signature) values (?1, ?2, ?3, ?4, ?5);"); | |
163 | insert.bind(1) = globid; | |
164 | insert.bind(2) = cd->identifier(); | |
165 | if (arch) | |
166 | insert.bind(3) = arch; | |
167 | insert.bind(4).blob(ident->data(), ident->length(), true); | |
168 | insert.bind(5).blob(sig, sig->length(), true); | |
169 | insert(); | |
170 | } | |
171 | ||
172 | ||
173 | ||
174 | } // end namespace CodeSigning | |
175 | } // end namespace Security |