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