]> git.saurik.com Git - apple/libsecurity_codesigning.git/blame_incremental - lib/resources.cpp
libsecurity_codesigning-55037.15.tar.gz
[apple/libsecurity_codesigning.git] / lib / resources.cpp
... / ...
CommitLineData
1/*
2 * Copyright (c) 2006-2010 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// resource directory construction and verification
26//
27#include "resources.h"
28#include "csutilities.h"
29#include <Security/CSCommon.h>
30#include <security_utilities/unix++.h>
31#include <security_utilities/cfmunge.h>
32
33namespace Security {
34namespace CodeSigning {
35
36
37//
38// Construction and maintainance
39//
40ResourceBuilder::ResourceBuilder(const std::string &root, CFDictionaryRef rulesDict, CodeDirectory::HashAlgorithm hashType)
41 : ResourceEnumerator(root), mHashType(hashType)
42{
43 CFDictionary rules(rulesDict, errSecCSResourceRulesInvalid);
44 rules.apply(this, &ResourceBuilder::addRule);
45 mRawRules = rules;
46}
47
48ResourceBuilder::~ResourceBuilder()
49{
50 for (Rules::iterator it = mRules.begin(); it != mRules.end(); ++it)
51 delete *it;
52}
53
54
55//
56// Parse and add one matching rule
57//
58void ResourceBuilder::addRule(CFTypeRef key, CFTypeRef value)
59{
60 string pattern = cfString(key, errSecCSResourceRulesInvalid);
61 unsigned weight = 1;
62 uint32_t flags = 0;
63 if (CFGetTypeID(value) == CFBooleanGetTypeID()) {
64 if (value == kCFBooleanFalse)
65 flags |= omitted;
66 } else {
67 CFDictionary rule(value, errSecCSResourceRulesInvalid);
68 if (CFNumberRef weightRef = rule.get<CFNumberRef>("weight"))
69 weight = cfNumber<unsigned int>(weightRef);
70 if (CFBooleanRef omitRef = rule.get<CFBooleanRef>("omit"))
71 if (omitRef == kCFBooleanTrue)
72 flags |= omitted;
73 if (CFBooleanRef optRef = rule.get<CFBooleanRef>("optional"))
74 if (optRef == kCFBooleanTrue)
75 flags |= optional;
76 }
77 addRule(new Rule(pattern, weight, flags));
78}
79
80
81//
82// Locate the next non-ignored file, look up its rule, and return it.
83// Returns NULL when we're out of files.
84//
85FTSENT *ResourceBuilder::next(string &path, Rule * &rule)
86{
87 while (FTSENT *ent = ResourceEnumerator::next(path)) {
88 // find best matching rule
89 Rule *bestRule = NULL;
90 for (Rules::const_iterator it = mRules.begin(); it != mRules.end(); ++it) {
91 Rule *rule = *it;
92 if (rule->match(path.c_str())) {
93 if (rule->flags & exclusion) {
94 bestRule = NULL;
95 break;
96 }
97 if (!bestRule || rule->weight > bestRule->weight)
98 bestRule = rule;
99 }
100 }
101 if (!bestRule || (bestRule->flags & omitted))
102 continue;
103 rule = bestRule;
104 return ent;
105 }
106 return NULL;
107}
108
109
110//
111// Build the ResourceDirectory given the currently established rule set.
112//
113CFDictionaryRef ResourceBuilder::build()
114{
115 secdebug("codesign", "start building resource directory");
116 CFRef<CFMutableDictionaryRef> files = makeCFMutableDictionary();
117
118 string path;
119 Rule *rule;
120 while (FTSENT *ent = next(path, rule)) {
121 assert(rule);
122 CFRef<CFDataRef> hash = hashFile(ent->fts_accpath);
123 if (rule->flags == 0) { // default case - plain hash
124 cfadd(files, "{%s=%O}", path.c_str(), hash.get());
125 secdebug("csresource", "%s added simple (rule %p)", path.c_str(), rule);
126 } else { // more complicated - use a sub-dictionary
127 cfadd(files, "{%s={hash=%O,optional=%B}}",
128 path.c_str(), hash.get(), rule->flags & optional);
129 secdebug("csresource", "%s added complex (rule %p)", path.c_str(), rule);
130 }
131 }
132 secdebug("codesign", "finished code directory with %d entries",
133 int(CFDictionaryGetCount(files)));
134
135 return cfmake<CFDictionaryRef>("{rules=%O,files=%O}", mRawRules.get(), files.get());
136}
137
138
139//
140// Hash a file and return a CFDataRef with the hash
141//
142CFDataRef ResourceBuilder::hashFile(const char *path)
143{
144 UnixPlusPlus::AutoFileDesc fd(path);
145 fd.fcntl(F_NOCACHE, true); // turn off page caching (one-pass)
146 MakeHash<ResourceBuilder> hasher(this);
147 hashFileData(fd, hasher.get());
148 Hashing::Byte digest[hasher->digestLength()];
149 hasher->finish(digest);
150 return CFDataCreate(NULL, digest, sizeof(digest));
151}
152
153
154//
155// Regex matching objects
156//
157ResourceBuilder::Rule::Rule(const std::string &pattern, unsigned w, uint32_t f)
158 : weight(w), flags(f)
159{
160 if (::regcomp(this, pattern.c_str(), REG_EXTENDED | REG_NOSUB)) //@@@ REG_ICASE?
161 MacOSError::throwMe(errSecCSResourceRulesInvalid);
162 secdebug("csresource", "%p rule %s added (weight %d, flags 0x%x)",
163 this, pattern.c_str(), w, f);
164}
165
166ResourceBuilder::Rule::~Rule()
167{
168 ::regfree(this);
169}
170
171bool ResourceBuilder::Rule::match(const char *s) const
172{
173 switch (::regexec(this, s, 0, NULL, 0)) {
174 case 0:
175 return true;
176 case REG_NOMATCH:
177 return false;
178 default:
179 MacOSError::throwMe(errSecCSResourceRulesInvalid);
180 }
181}
182
183
184std::string ResourceBuilder::escapeRE(const std::string &s)
185{
186 string r;
187 for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
188 char c = *it;
189 if (strchr("\\[]{}().+*", c))
190 r.push_back('\\');
191 r.push_back(c);
192 }
193 return r;
194}
195
196
197//
198// Resource Seals
199//
200ResourceSeal::ResourceSeal(CFTypeRef it)
201{
202 if (it == NULL)
203 MacOSError::throwMe(errSecCSResourcesInvalid);
204 if (CFGetTypeID(it) == CFDataGetTypeID()) {
205 mHash = CFDataRef(it);
206 mOptional = false;
207 } else {
208 mOptional = false;
209 if (!cfscan(it, "{hash=%XO,?optional=%B}", &mHash, &mOptional))
210 MacOSError::throwMe(errSecCSResourcesInvalid);
211 }
212}
213
214
215} // end namespace CodeSigning
216} // end namespace Security