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