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