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 // A helper for parsing out a CFDictionary signing-data specification
47 class SecCodeSigner::Parser
: CFDictionary
{
49 Parser(SecCodeSigner
&signer
, CFDictionaryRef parameters
);
51 bool getBool(CFStringRef key
) const
53 if (CFBooleanRef flag
= get
<CFBooleanRef
>(key
))
54 return flag
== kCFBooleanTrue
;
62 // Construct a SecCodeSigner
64 SecCodeSigner::SecCodeSigner()
67 secdebug("signer", "%p created", this);
72 // Clean up a SecCodeSigner
74 SecCodeSigner::~SecCodeSigner() throw()
76 secdebug("signer", "%p destroyed", this);
77 ::free((Requirements
*)mRequirements
);
82 // Parse an input parameter dictionary and set ready-to-use parameters
84 void SecCodeSigner::parameters(CFDictionaryRef paramDict
)
86 secdebug("signer", "%p loading %d parameters", this, int(CFDictionaryGetCount(paramDict
)));
87 Parser(*this, paramDict
);
89 MacOSError::throwMe(errSecCSInvalidObjectRef
);
96 void SecCodeSigner::sign(SecStaticCode
*code
, SecCSFlags flags
)
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();
107 // ReturnDetachedSignature is called by writers or editors that try to return
108 // detached signature data (rather than annotate the target).
110 void SecCodeSigner::returnDetachedSignature(BlobCore
*blob
)
113 if (CFGetTypeID(mDetached
) == CFURLGetTypeID()) {
114 // URL to destination file
115 AutoFileDesc
fd(cfString(CFURLRef(mDetached
.get())), O_WRONLY
| O_CREAT
| O_TRUNC
);
117 } else if (CFGetTypeID(mDetached
) == CFDataGetTypeID()) {
118 CFDataAppendBytes(CFMutableDataRef(mDetached
.get()),
119 (const UInt8
*)blob
, blob
->length());
126 // The actual parsing operation is done in the Parser class.
128 // Note that we need to copy or retain all incoming data. The caller has no requirement
129 // to keep the parameters dictionary around.
131 SecCodeSigner::Parser::Parser(SecCodeSigner
&state
, CFDictionaryRef parameters
)
132 : CFDictionary(parameters
, errSecCSBadDictionaryFormat
)
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
);
139 MacOSError::throwMe(errSecCSInvalidObjectRef
);
141 MacOSError::throwMe(errSecCSInvalidObjectRef
);
143 // the flags need some augmentation
144 if (CFNumberRef flags
= get
<CFNumberRef
>(kSecCodeSignerFlags
)) {
145 state
.mCdFlagsGiven
= true;
146 state
.mCdFlags
= cfNumber
<uint32_t>(flags
);
148 state
.mCdFlagsGiven
= false;
150 if (CFNumberRef cmsSize
= get
<CFNumberRef
>(CFSTR("cmssize")))
151 state
.mCMSSize
= cfNumber
<size_t>(cmsSize
);
153 state
.mCMSSize
= 5000; // likely big enough
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
);
160 MacOSError::throwMe(errSecCSInvalidObjectRef
);
162 if (CFStringRef ident
= get
<CFStringRef
>(kSecCodeSignerIdentifier
))
163 state
.mIdentifier
= cfString(ident
);
165 if (CFStringRef prefix
= get
<CFStringRef
>(kSecCodeSignerIdentifierPrefix
))
166 state
.mIdentifierPrefix
= cfString(prefix
);
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
)));
176 MacOSError::throwMe(errSecCSInvalidObjectRef
);
178 state
.mRequirements
= NULL
;
180 state
.mNoMachO
= getBool(CFSTR("no-macho"));
182 state
.mPageSize
= get
<CFNumberRef
>(kSecCodeSignerPageSize
);
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
);
191 state
.mDryRun
= getBool(kSecCodeSignerDryRun
);
193 state
.mResourceRules
= get
<CFDictionaryRef
>(kSecCodeSignerResourceRules
);
195 state
.mApplicationData
= get
<CFDataRef
>(kSecCodeSignerApplicationData
);
196 state
.mEntitlementData
= get
<CFDataRef
>(kSecCodeSignerEntitlements
);
200 } // end namespace CodeSigning
201 } // end namespace Security