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 "csdatabase.h"
32 #include <security_utilities/unix++.h>
33 #include <security_utilities/unixchild.h>
38 __SEC_CFTYPE(SecIdentity
)
40 namespace CodeSigning
{
42 using namespace UnixPlusPlus
;
46 // A helper for parsing out a CFDictionary signing-data specification
48 class SecCodeSigner::Parser
: CFDictionary
{
50 Parser(SecCodeSigner
&signer
, CFDictionaryRef parameters
);
52 bool getBool(CFStringRef key
) const
54 if (CFBooleanRef flag
= get
<CFBooleanRef
>(key
))
55 return flag
== kCFBooleanTrue
;
63 // Construct a SecCodeSigner
65 SecCodeSigner::SecCodeSigner(SecCSFlags flags
)
66 : mOpFlags(flags
), mRequirements(NULL
)
72 // Clean up a SecCodeSigner
74 SecCodeSigner::~SecCodeSigner() throw()
76 ::free((Requirements
*)mRequirements
);
81 // Parse an input parameter dictionary and set ready-to-use parameters
83 void SecCodeSigner::parameters(CFDictionaryRef paramDict
)
85 Parser(*this, paramDict
);
87 MacOSError::throwMe(errSecCSInvalidObjectRef
);
92 // Roughly check for validity.
93 // This isn't thorough; it just sees if if looks like we've set up the object appropriately.
95 bool SecCodeSigner::valid() const
97 if (mOpFlags
& kSecCSRemoveSignature
)
106 void SecCodeSigner::sign(SecStaticCode
*code
, SecCSFlags flags
)
108 Signer
operation(*this, code
);
109 if ((flags
| mOpFlags
) & kSecCSRemoveSignature
) {
110 secdebug("signer", "%p will remove signature from %p", this, code
);
111 operation
.remove(flags
);
114 MacOSError::throwMe(errSecCSInvalidObjectRef
);
115 secdebug("signer", "%p will sign %p (flags 0x%x)", this, code
, flags
);
116 operation
.sign(flags
);
118 code
->resetValidity();
123 // ReturnDetachedSignature is called by writers or editors that try to return
124 // detached signature data (rather than annotate the target).
126 void SecCodeSigner::returnDetachedSignature(BlobCore
*blob
, Signer
&signer
)
129 if (CFGetTypeID(mDetached
) == CFURLGetTypeID()) {
130 // URL to destination file
131 AutoFileDesc
fd(cfString(CFURLRef(mDetached
.get())), O_WRONLY
| O_CREAT
| O_TRUNC
);
133 } else if (CFGetTypeID(mDetached
) == CFDataGetTypeID()) {
134 CFDataAppendBytes(CFMutableDataRef(mDetached
.get()),
135 (const UInt8
*)blob
, blob
->length());
136 } else if (CFGetTypeID(mDetached
) == CFNullGetTypeID()) {
137 signatureDatabase().storeCode(blob
, signer
.path().c_str());
144 // The actual parsing operation is done in the Parser class.
146 // Note that we need to copy or retain all incoming data. The caller has no requirement
147 // to keep the parameters dictionary around.
149 SecCodeSigner::Parser::Parser(SecCodeSigner
&state
, CFDictionaryRef parameters
)
150 : CFDictionary(parameters
, errSecCSBadDictionaryFormat
)
152 // the signer may be an identity or null
153 if (CFTypeRef signer
= get
<CFTypeRef
>(kSecCodeSignerIdentity
))
154 if (CFGetTypeID(signer
) == SecIdentityGetTypeID() || signer
== kCFNull
)
155 state
.mSigner
= SecIdentityRef(signer
);
157 MacOSError::throwMe(errSecCSInvalidObjectRef
);
159 // the flags need some augmentation
160 if (CFNumberRef flags
= get
<CFNumberRef
>(kSecCodeSignerFlags
)) {
161 state
.mCdFlagsGiven
= true;
162 state
.mCdFlags
= cfNumber
<uint32_t>(flags
);
164 state
.mCdFlagsGiven
= false;
166 if (CFNumberRef cmsSize
= get
<CFNumberRef
>(CFSTR("cmssize")))
167 state
.mCMSSize
= cfNumber
<size_t>(cmsSize
);
169 state
.mCMSSize
= 5000; // likely big enough
171 // signing time can be a CFDateRef or null
172 if (CFTypeRef time
= get
<CFTypeRef
>(kSecCodeSignerSigningTime
))
173 if (CFGetTypeID(time
) == CFDateGetTypeID() || time
== kCFNull
)
174 state
.mSigningTime
= CFDateRef(time
);
176 MacOSError::throwMe(errSecCSInvalidObjectRef
);
178 if (CFStringRef ident
= get
<CFStringRef
>(kSecCodeSignerIdentifier
))
179 state
.mIdentifier
= cfString(ident
);
181 if (CFStringRef prefix
= get
<CFStringRef
>(kSecCodeSignerIdentifierPrefix
))
182 state
.mIdentifierPrefix
= cfString(prefix
);
184 // requirements can be binary or string (to be compiled)
185 if (CFTypeRef reqs
= get
<CFTypeRef
>(kSecCodeSignerRequirements
)) {
186 if (CFGetTypeID(reqs
) == CFDataGetTypeID()) { // binary form
187 const Requirements
*rp
= (const Requirements
*)CFDataGetBytePtr(CFDataRef(reqs
));
188 state
.mRequirements
= rp
->clone();
189 } else if (CFGetTypeID(reqs
) == CFStringGetTypeID()) { // text form
190 state
.mRequirements
= parseRequirements(cfString(CFStringRef(reqs
)));
192 MacOSError::throwMe(errSecCSInvalidObjectRef
);
194 state
.mRequirements
= NULL
;
196 state
.mNoMachO
= getBool(CFSTR("no-macho"));
198 state
.mPageSize
= get
<CFNumberRef
>(kSecCodeSignerPageSize
);
200 // detached can be (destination) file URL or (mutable) Data to be appended-to
201 if (state
.mDetached
= get
<CFTypeRef
>(kSecCodeSignerDetached
)) {
202 CFTypeID type
= CFGetTypeID(state
.mDetached
);
203 if (type
!= CFURLGetTypeID() && type
!= CFDataGetTypeID() && type
!= CFNullGetTypeID())
204 MacOSError::throwMe(errSecCSInvalidObjectRef
);
207 state
.mDryRun
= getBool(kSecCodeSignerDryRun
);
209 state
.mResourceRules
= get
<CFDictionaryRef
>(kSecCodeSignerResourceRules
);
211 state
.mApplicationData
= get
<CFDataRef
>(kSecCodeSignerApplicationData
);
212 state
.mEntitlementData
= get
<CFDataRef
>(kSecCodeSignerEntitlements
);
216 } // end namespace CodeSigning
217 } // end namespace Security