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