2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 // CodeSigner - SecCodeSigner API objects
27 #include "CodeSigner.h"
29 #include "reqparser.h"
31 #include <security_utilities/unix++.h>
32 #include <security_utilities/unixchild.h>
37 __SEC_CFTYPE(SecIdentity
)
39 namespace CodeSigning
{
41 using namespace UnixPlusPlus
;
45 // The allocation helper
47 static const char helperName
[] = "codesign_allocate";
48 static const char helperPath
[] = "/usr/bin/codesign_allocate";
49 static const size_t csAlign
= 16;
53 // A helper for parsing out a CFDictionary signing-data specification
55 class SecCodeSigner::Parser
: CFDictionary
{
57 Parser(SecCodeSigner
&signer
, CFDictionaryRef parameters
);
59 bool getBool(CFStringRef key
) const
61 if (CFBooleanRef flag
= get
<CFBooleanRef
>(key
))
62 return flag
== kCFBooleanTrue
;
70 // Construct a SecCodeSigner
72 SecCodeSigner::SecCodeSigner()
75 secdebug("signer", "%p created", this);
80 // Clean up a SecCodeSigner
82 SecCodeSigner::~SecCodeSigner() throw()
84 secdebug("signer", "%p destroyed", this);
85 ::free((Requirements
*)mRequirements
);
90 // Parse an input parameter dictionary and set ready-to-use parameters
92 void SecCodeSigner::parameters(CFDictionaryRef paramDict
)
94 secdebug("signer", "%p loading %d parameters", this, int(CFDictionaryGetCount(paramDict
)));
95 Parser(*this, paramDict
);
97 MacOSError::throwMe(errSecCSInvalidObjectRef
);
104 void SecCodeSigner::sign(SecStaticCode
*code
, SecCSFlags flags
)
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();
115 // ReturnDetachedSignature is called by writers or editors that try to return
116 // detached signature data (rather than annotate the target).
118 void SecCodeSigner::returnDetachedSignature(BlobCore
*blob
)
121 if (CFGetTypeID(mDetached
) == CFURLGetTypeID()) {
122 // URL to destination file
123 AutoFileDesc
fd(cfString(CFURLRef(mDetached
.get())), O_WRONLY
| O_CREAT
| O_TRUNC
);
125 } else if (CFGetTypeID(mDetached
) == CFDataGetTypeID()) {
126 CFDataAppendBytes(CFMutableDataRef(mDetached
.get()),
127 (const UInt8
*)blob
, blob
->length());
134 // The actual parsing operation is done in the Parser class.
136 // Note that we need to copy or retain all incoming data. The caller has no requirement
137 // to keep the parameters dictionary around.
139 SecCodeSigner::Parser::Parser(SecCodeSigner
&state
, CFDictionaryRef parameters
)
140 : CFDictionary(parameters
, errSecCSBadDictionaryFormat
)
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
);
147 MacOSError::throwMe(errSecCSInvalidObjectRef
);
149 MacOSError::throwMe(errSecCSInvalidObjectRef
);
151 // the flags need some augmentation
152 if (CFNumberRef flags
= get
<CFNumberRef
>(kSecCodeSignerFlags
)) {
153 state
.mCdFlagsGiven
= true;
154 state
.mCdFlags
= cfNumber
<uint32_t>(flags
);
156 state
.mCdFlagsGiven
= false;
158 if (CFNumberRef cmsSize
= get
<CFNumberRef
>(CFSTR("cmssize")))
159 state
.mCMSSize
= cfNumber
<size_t>(cmsSize
);
161 state
.mCMSSize
= 5000; // likely big enough
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
);
168 MacOSError::throwMe(errSecCSInvalidObjectRef
);
170 if (CFStringRef ident
= get
<CFStringRef
>(kSecCodeSignerIdentifier
))
171 state
.mIdentifier
= cfString(ident
);
173 if (CFStringRef prefix
= get
<CFStringRef
>(kSecCodeSignerIdentifierPrefix
))
174 state
.mIdentifierPrefix
= cfString(prefix
);
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
)));
184 MacOSError::throwMe(errSecCSInvalidObjectRef
);
186 state
.mRequirements
= NULL
;
188 state
.mNoMachO
= getBool(CFSTR("no-macho"));
190 state
.mPageSize
= get
<CFNumberRef
>(kSecCodeSignerPageSize
);
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
);
199 state
.mDryRun
= getBool(kSecCodeSignerDryRun
);
201 state
.mResourceRules
= get
<CFDictionaryRef
>(kSecCodeSignerResourceRules
);
203 state
.mApplicationData
= get
<CFDataRef
>(kSecCodeSignerApplicationData
);
207 } // end namespace CodeSigning
208 } // end namespace Security