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