]> git.saurik.com Git - apple/security.git/blob - libsecurity_codesigning/lib/CodeSigner.cpp
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_codesigning / lib / CodeSigner.cpp
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 // 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 "drmaker.h"
33 #include "csutilities.h"
34 #include <security_utilities/unix++.h>
35 #include <security_utilities/unixchild.h>
36 #include <Security/SecCertificate.h>
37 #include <vector>
38
39 namespace Security {
40
41 __SEC_CFTYPE(SecIdentity)
42
43 namespace CodeSigning {
44
45 using namespace UnixPlusPlus;
46
47
48 //
49 // A helper for parsing out a CFDictionary signing-data specification
50 //
51 class SecCodeSigner::Parser : CFDictionary {
52 public:
53 Parser(SecCodeSigner &signer, CFDictionaryRef parameters);
54
55 bool getBool(CFStringRef key) const
56 {
57 if (CFBooleanRef flag = get<CFBooleanRef>(key))
58 return flag == kCFBooleanTrue;
59 else
60 return false;
61 }
62 };
63
64
65 //
66 // Construct a SecCodeSigner
67 //
68 SecCodeSigner::SecCodeSigner(SecCSFlags flags)
69 : mOpFlags(flags), mRequirements(NULL), mDigestAlgorithm(kSecCodeSignatureDefaultDigestAlgorithm)
70 {
71 }
72
73
74 //
75 // Clean up a SecCodeSigner
76 //
77 SecCodeSigner::~SecCodeSigner() throw()
78 try {
79 ::free((Requirements *)mRequirements);
80 } catch (...) {
81 return;
82 }
83
84
85 //
86 // Parse an input parameter dictionary and set ready-to-use parameters
87 //
88 void SecCodeSigner::parameters(CFDictionaryRef paramDict)
89 {
90 Parser(*this, paramDict);
91 if (!valid())
92 MacOSError::throwMe(errSecCSInvalidObjectRef);
93 }
94
95
96 //
97 // Roughly check for validity.
98 // This isn't thorough; it just sees if if looks like we've set up the object appropriately.
99 //
100 bool SecCodeSigner::valid() const
101 {
102 if (mOpFlags & kSecCSRemoveSignature)
103 return true;
104 return mSigner;
105 }
106
107
108 //
109 // Sign code
110 //
111 void SecCodeSigner::sign(SecStaticCode *code, SecCSFlags flags)
112 {
113 Signer operation(*this, code);
114 if ((flags | mOpFlags) & kSecCSRemoveSignature) {
115 secdebug("signer", "%p will remove signature from %p", this, code);
116 operation.remove(flags);
117 } else {
118 if (!valid())
119 MacOSError::throwMe(errSecCSInvalidObjectRef);
120 secdebug("signer", "%p will sign %p (flags 0x%x)", this, code, flags);
121 operation.sign(flags);
122 }
123 code->resetValidity();
124 }
125
126
127 //
128 // ReturnDetachedSignature is called by writers or editors that try to return
129 // detached signature data (rather than annotate the target).
130 //
131 void SecCodeSigner::returnDetachedSignature(BlobCore *blob, Signer &signer)
132 {
133 assert(mDetached);
134 if (CFGetTypeID(mDetached) == CFURLGetTypeID()) {
135 // URL to destination file
136 AutoFileDesc fd(cfString(CFURLRef(mDetached.get())), O_WRONLY | O_CREAT | O_TRUNC);
137 fd.writeAll(*blob);
138 } else if (CFGetTypeID(mDetached) == CFDataGetTypeID()) {
139 CFDataAppendBytes(CFMutableDataRef(mDetached.get()),
140 (const UInt8 *)blob, blob->length());
141 } else if (CFGetTypeID(mDetached) == CFNullGetTypeID()) {
142 signatureDatabaseWriter().storeCode(blob, signer.path().c_str());
143 } else
144 assert(false);
145 }
146
147
148 //
149 // Our DiskRep::signingContext methods communicate with the signing subsystem
150 // in terms those callers can easily understand.
151 //
152 string SecCodeSigner::sdkPath(const std::string &path) const
153 {
154 assert(path[0] == '/'); // need absolute path here
155 if (mSDKRoot)
156 return cfString(mSDKRoot) + path;
157 else
158 return path;
159 }
160
161 bool SecCodeSigner::isAdhoc() const
162 {
163 return mSigner == SecIdentityRef(kCFNull);
164 }
165
166
167 //
168 // The actual parsing operation is done in the Parser class.
169 //
170 // Note that we need to copy or retain all incoming data. The caller has no requirement
171 // to keep the parameters dictionary around.
172 //
173 SecCodeSigner::Parser::Parser(SecCodeSigner &state, CFDictionaryRef parameters)
174 : CFDictionary(parameters, errSecCSBadDictionaryFormat)
175 {
176 // the signer may be an identity or null
177 state.mSigner = SecIdentityRef(get<CFTypeRef>(kSecCodeSignerIdentity));
178 if (state.mSigner)
179 if (CFGetTypeID(state.mSigner) != SecIdentityGetTypeID() && !CFEqual(state.mSigner, kCFNull))
180 MacOSError::throwMe(errSecCSInvalidObjectRef);
181
182 // the flags need some augmentation
183 if (CFNumberRef flags = get<CFNumberRef>(kSecCodeSignerFlags)) {
184 state.mCdFlagsGiven = true;
185 state.mCdFlags = cfNumber<uint32_t>(flags);
186 } else
187 state.mCdFlagsGiven = false;
188
189 // digest algorithms are specified as a numeric code
190 if (CFNumberRef digestAlgorithm = get<CFNumberRef>(kSecCodeSignerDigestAlgorithm))
191 state.mDigestAlgorithm = cfNumber<unsigned int>(digestAlgorithm);
192
193 if (CFNumberRef cmsSize = get<CFNumberRef>(CFSTR("cmssize")))
194 state.mCMSSize = cfNumber<size_t>(cmsSize);
195 else
196 state.mCMSSize = 9000; // likely big enough
197
198 // signing time can be a CFDateRef or null
199 if (CFTypeRef time = get<CFTypeRef>(kSecCodeSignerSigningTime)) {
200 if (CFGetTypeID(time) == CFDateGetTypeID() || time == kCFNull)
201 state.mSigningTime = CFDateRef(time);
202 else
203 MacOSError::throwMe(errSecCSInvalidObjectRef);
204 }
205
206 if (CFStringRef ident = get<CFStringRef>(kSecCodeSignerIdentifier))
207 state.mIdentifier = cfString(ident);
208
209 if (CFStringRef prefix = get<CFStringRef>(kSecCodeSignerIdentifierPrefix))
210 state.mIdentifierPrefix = cfString(prefix);
211
212 // requirements can be binary or string (to be compiled)
213 if (CFTypeRef reqs = get<CFTypeRef>(kSecCodeSignerRequirements)) {
214 if (CFGetTypeID(reqs) == CFDataGetTypeID()) { // binary form
215 const Requirements *rp = (const Requirements *)CFDataGetBytePtr(CFDataRef(reqs));
216 state.mRequirements = rp->clone();
217 } else if (CFGetTypeID(reqs) == CFStringGetTypeID()) { // text form
218 state.mRequirements = parseRequirements(cfString(CFStringRef(reqs)));
219 } else
220 MacOSError::throwMe(errSecCSInvalidObjectRef);
221 } else
222 state.mRequirements = NULL;
223
224 state.mNoMachO = getBool(CFSTR("no-macho"));
225
226 state.mPageSize = get<CFNumberRef>(kSecCodeSignerPageSize);
227
228 // detached can be (destination) file URL or (mutable) Data to be appended-to
229 if ((state.mDetached = get<CFTypeRef>(kSecCodeSignerDetached))) {
230 CFTypeID type = CFGetTypeID(state.mDetached);
231 if (type != CFURLGetTypeID() && type != CFDataGetTypeID() && type != CFNullGetTypeID())
232 MacOSError::throwMe(errSecCSInvalidObjectRef);
233 }
234
235 state.mDryRun = getBool(kSecCodeSignerDryRun);
236
237 state.mResourceRules = get<CFDictionaryRef>(kSecCodeSignerResourceRules);
238
239 state.mApplicationData = get<CFDataRef>(kSecCodeSignerApplicationData);
240 state.mEntitlementData = get<CFDataRef>(kSecCodeSignerEntitlements);
241
242 state.mSDKRoot = get<CFURLRef>(kSecCodeSignerSDKRoot);
243
244 if (CFBooleanRef timestampRequest = get<CFBooleanRef>(kSecCodeSignerRequireTimestamp)) {
245 state.mWantTimeStamp = timestampRequest == kCFBooleanTrue;
246 } else { // pick default
247 state.mWantTimeStamp = false;
248 if (state.mSigner && state.mSigner != SecIdentityRef(kCFNull)) {
249 CFRef<SecCertificateRef> signerCert;
250 MacOSError::check(SecIdentityCopyCertificate(state.mSigner, &signerCert.aref()));
251 if (certificateHasField(signerCert, devIdLeafMarkerOID))
252 state.mWantTimeStamp = true;
253 }
254 }
255 state.mTimestampAuthentication = get<SecIdentityRef>(kSecCodeSignerTimestampAuthentication);
256 state.mTimestampService = get<CFURLRef>(kSecCodeSignerTimestampServer);
257 state.mNoTimeStampCerts = getBool(kSecCodeSignerTimestampOmitCertificates);
258 }
259
260
261 } // end namespace CodeSigning
262 } // end namespace Security