]> git.saurik.com Git - apple/libsecurity_codesigning.git/blob - lib/CodeSigner.cpp
f2ff65b48f18f3d59b166fd66de59415f0bf21ab
[apple/libsecurity_codesigning.git] / lib / CodeSigner.cpp
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 // CodeSigner - SecCodeSigner API objects
26 //
27 #include "CodeSigner.h"
28 #include "signer.h"
29 #include "reqparser.h"
30 #include "renum.h"
31 #include "csdatabase.h"
32 #include <security_utilities/unix++.h>
33 #include <security_utilities/unixchild.h>
34 #include <vector>
35
36 namespace Security {
37
38 __SEC_CFTYPE(SecIdentity)
39
40 namespace CodeSigning {
41
42 using namespace UnixPlusPlus;
43
44
45 //
46 // A helper for parsing out a CFDictionary signing-data specification
47 //
48 class SecCodeSigner::Parser : CFDictionary {
49 public:
50 Parser(SecCodeSigner &signer, CFDictionaryRef parameters);
51
52 bool getBool(CFStringRef key) const
53 {
54 if (CFBooleanRef flag = get<CFBooleanRef>(key))
55 return flag == kCFBooleanTrue;
56 else
57 return false;
58 }
59 };
60
61
62 //
63 // Construct a SecCodeSigner
64 //
65 SecCodeSigner::SecCodeSigner(SecCSFlags flags)
66 : mOpFlags(flags), mRequirements(NULL)
67 {
68 }
69
70
71 //
72 // Clean up a SecCodeSigner
73 //
74 SecCodeSigner::~SecCodeSigner() throw()
75 {
76 ::free((Requirements *)mRequirements);
77 }
78
79
80 //
81 // Parse an input parameter dictionary and set ready-to-use parameters
82 //
83 void SecCodeSigner::parameters(CFDictionaryRef paramDict)
84 {
85 Parser(*this, paramDict);
86 if (!valid())
87 MacOSError::throwMe(errSecCSInvalidObjectRef);
88 }
89
90
91 //
92 // Roughly check for validity.
93 // This isn't thorough; it just sees if if looks like we've set up the object appropriately.
94 //
95 bool SecCodeSigner::valid() const
96 {
97 if (mOpFlags & kSecCSRemoveSignature)
98 return true;
99 return mSigner;
100 }
101
102
103 //
104 // Sign code
105 //
106 void SecCodeSigner::sign(SecStaticCode *code, SecCSFlags flags)
107 {
108 Signer operation(*this, code);
109 if ((flags | mOpFlags) & kSecCSRemoveSignature) {
110 secdebug("signer", "%p will remove signature from %p", this, code);
111 operation.remove(flags);
112 } else {
113 if (!valid())
114 MacOSError::throwMe(errSecCSInvalidObjectRef);
115 secdebug("signer", "%p will sign %p (flags 0x%x)", this, code, flags);
116 operation.sign(flags);
117 }
118 code->resetValidity();
119 }
120
121
122 //
123 // ReturnDetachedSignature is called by writers or editors that try to return
124 // detached signature data (rather than annotate the target).
125 //
126 void SecCodeSigner::returnDetachedSignature(BlobCore *blob, Signer &signer)
127 {
128 assert(mDetached);
129 if (CFGetTypeID(mDetached) == CFURLGetTypeID()) {
130 // URL to destination file
131 AutoFileDesc fd(cfString(CFURLRef(mDetached.get())), O_WRONLY | O_CREAT | O_TRUNC);
132 fd.writeAll(*blob);
133 } else if (CFGetTypeID(mDetached) == CFDataGetTypeID()) {
134 CFDataAppendBytes(CFMutableDataRef(mDetached.get()),
135 (const UInt8 *)blob, blob->length());
136 } else if (CFGetTypeID(mDetached) == CFNullGetTypeID()) {
137 signatureDatabase().storeCode(blob, signer.path().c_str());
138 } else
139 assert(false);
140 }
141
142
143 //
144 // The actual parsing operation is done in the Parser class.
145 //
146 // Note that we need to copy or retain all incoming data. The caller has no requirement
147 // to keep the parameters dictionary around.
148 //
149 SecCodeSigner::Parser::Parser(SecCodeSigner &state, CFDictionaryRef parameters)
150 : CFDictionary(parameters, errSecCSBadDictionaryFormat)
151 {
152 // the signer may be an identity or null
153 if (CFTypeRef signer = get<CFTypeRef>(kSecCodeSignerIdentity))
154 if (CFGetTypeID(signer) == SecIdentityGetTypeID() || signer == kCFNull)
155 state.mSigner = SecIdentityRef(signer);
156 else
157 MacOSError::throwMe(errSecCSInvalidObjectRef);
158
159 // the flags need some augmentation
160 if (CFNumberRef flags = get<CFNumberRef>(kSecCodeSignerFlags)) {
161 state.mCdFlagsGiven = true;
162 state.mCdFlags = cfNumber<uint32_t>(flags);
163 } else
164 state.mCdFlagsGiven = false;
165
166 if (CFNumberRef cmsSize = get<CFNumberRef>(CFSTR("cmssize")))
167 state.mCMSSize = cfNumber<size_t>(cmsSize);
168 else
169 state.mCMSSize = 5000; // likely big enough
170
171 // signing time can be a CFDateRef or null
172 if (CFTypeRef time = get<CFTypeRef>(kSecCodeSignerSigningTime))
173 if (CFGetTypeID(time) == CFDateGetTypeID() || time == kCFNull)
174 state.mSigningTime = CFDateRef(time);
175 else
176 MacOSError::throwMe(errSecCSInvalidObjectRef);
177
178 if (CFStringRef ident = get<CFStringRef>(kSecCodeSignerIdentifier))
179 state.mIdentifier = cfString(ident);
180
181 if (CFStringRef prefix = get<CFStringRef>(kSecCodeSignerIdentifierPrefix))
182 state.mIdentifierPrefix = cfString(prefix);
183
184 // requirements can be binary or string (to be compiled)
185 if (CFTypeRef reqs = get<CFTypeRef>(kSecCodeSignerRequirements)) {
186 if (CFGetTypeID(reqs) == CFDataGetTypeID()) { // binary form
187 const Requirements *rp = (const Requirements *)CFDataGetBytePtr(CFDataRef(reqs));
188 state.mRequirements = rp->clone();
189 } else if (CFGetTypeID(reqs) == CFStringGetTypeID()) { // text form
190 state.mRequirements = parseRequirements(cfString(CFStringRef(reqs)));
191 } else
192 MacOSError::throwMe(errSecCSInvalidObjectRef);
193 } else
194 state.mRequirements = NULL;
195
196 state.mNoMachO = getBool(CFSTR("no-macho"));
197
198 state.mPageSize = get<CFNumberRef>(kSecCodeSignerPageSize);
199
200 // detached can be (destination) file URL or (mutable) Data to be appended-to
201 if (state.mDetached = get<CFTypeRef>(kSecCodeSignerDetached)) {
202 CFTypeID type = CFGetTypeID(state.mDetached);
203 if (type != CFURLGetTypeID() && type != CFDataGetTypeID() && type != CFNullGetTypeID())
204 MacOSError::throwMe(errSecCSInvalidObjectRef);
205 }
206
207 state.mDryRun = getBool(kSecCodeSignerDryRun);
208
209 state.mResourceRules = get<CFDictionaryRef>(kSecCodeSignerResourceRules);
210
211 state.mApplicationData = get<CFDataRef>(kSecCodeSignerApplicationData);
212 state.mEntitlementData = get<CFDataRef>(kSecCodeSignerEntitlements);
213 }
214
215
216 } // end namespace CodeSigning
217 } // end namespace Security