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