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