1/* 2 * Copyright (c) 2006-2010 Apple 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// cs_sign - codesign signing operation 26// 27#include "codesign.h" 28#include "cs_utils.h" 29#include <Security/Security.h> 30#include <Security/SecCodeSigner.h> 31#include <Security/SecCodePriv.h> 32#include <Security/SecRequirementPriv.h> 33#include <Security/CSCommonPriv.h> 34#include <security_utilities/blob.h> 35#include <security_utilities/cfmunge.h> 36#include <cstdio> 37#include <cmath> 38 39using namespace UnixPlusPlus; 40 41 42// 43// One-time preparation 44// 45static CFMutableDictionaryRef parameters; // common signing parameters 46static SecCodeSignerRef signerRef; // global signer object 47 48void prepareToSign() 49{ 50 parameters = makeCFMutableDictionary(); 51 SecCSFlags flags = signOptions; 52 53 if (!force) 54 flags |= kSecCSSignPreserveSignature; 55 56 if (signer) 57 CFDictionaryAddValue(parameters, 58 kSecCodeSignerIdentity, signer); 59 else 60 flags |= kSecCSRemoveSignature; 61 62 if (uniqueIdentifier) 63 CFDictionaryAddValue(parameters, 64 kSecCodeSignerIdentifier, CFTempString(uniqueIdentifier)); 65 if (identifierPrefix) 66 CFDictionaryAddValue(parameters, 67 kSecCodeSignerIdentifierPrefix, CFTempString(identifierPrefix)); 68 69 if (teamID) { 70 CFDictionaryAddValue(parameters, 71 kSecCodeSignerTeamIdentifier, CFTempString(teamID)); 72 } 73 74 if (internalReq) 75 CFDictionaryAddValue(parameters, 76 kSecCodeSignerRequirements, readRequirement(internalReq, 0)); 77 78 if (signatureSize) 79 CFDictionaryAddValue(parameters, CFSTR("cmssize"), CFTempNumber(signatureSize)); 80 if (pagesize != pagesizeUnspecified) 81 CFDictionaryAddValue(parameters, kSecCodeSignerPageSize, CFTempNumber(pagesize)); 82 if (cdFlags) 83 CFDictionaryAddValue(parameters, kSecCodeSignerFlags, CFTempNumber(cdFlags)); 84 if (digestAlgorithm) 85 CFDictionaryAddValue(parameters, kSecCodeSignerDigestAlgorithm, CFTempNumber(digestAlgorithm)); 86 if (preserveMetadata) 87 CFDictionaryAddValue(parameters, kSecCodeSignerPreserveMetadata, CFTempNumber(preserveMetadata)); 88 if (signingTime) 89 CFDictionaryAddValue(parameters, kSecCodeSignerSigningTime, signingTime); 90 91 if (detached) 92 CFDictionaryAddValue(parameters, kSecCodeSignerDetached, CFTempURL(detached)); 93 else if (detachedDb) 94 CFDictionaryAddValue(parameters, kSecCodeSignerDetached, kCFNull); 95 96 if (timestampRequest) { 97 CFDictionaryAddValue(parameters, kSecCodeSignerRequireTimestamp, timestampRequest); 98 if (signingTime && signingTime != CFDateRef(kCFNull)) 99 fail("explicit signing time not allowed with timestamp service"); 100 } 101 if (tsaURL) 102 CFDictionaryAddValue(parameters, kSecCodeSignerTimestampServer, CFTempURL(tsaURL)); 103 if (noTSAcerts) 104 CFDictionaryAddValue(parameters, kSecCodeSignerTimestampOmitCertificates, kCFBooleanTrue); 105 106 if (resourceRules) { 107 if (CFRef<CFDataRef> data = cfLoadFile(resourceRules)) { 108 CFDictionaryAddValue(parameters, kSecCodeSignerResourceRules, 109 CFRef<CFDictionaryRef>(makeCFDictionaryFrom(data))); 110 } else 111 fail("%s: cannot read resources", resourceRules); 112 } 113 114 if (!sdkRoot) 115 if (const char *envroot = getenv("SDKDIR")) 116 sdkRoot = envroot; 117 if (sdkRoot) { 118 struct stat st; 119 if (::stat(sdkRoot, &st)) 120 fail("%s: %s", sdkRoot, strerror(errno)); 121 CFDictionaryAddValue(parameters, kSecCodeSignerSDKRoot, CFTempURL(sdkRoot, true)); 122 } 123 124 if (entitlements) { 125 if (CFRef<CFDataRef> data = cfLoadFile(entitlements)) { // load the proposed entitlement blob 126 if (CFRef<CFDictionaryRef> dict = makeCFDictionaryFrom(data)) { 127 // plain plist - (silently) wrap into canonical blob form 128 BlobWrapper *wrap = BlobWrapper::alloc(CFDataGetBytePtr(data), CFDataGetLength(data), kSecCodeMagicEntitlement); 129 CFDictionaryAddValue(parameters, kSecCodeSignerEntitlements, CFTempData(*(BlobCore*)wrap)); 130 ::free(wrap); 131 } else { 132 const BlobCore *blob = reinterpret_cast<const BlobCore *>(CFDataGetBytePtr(data)); 133 if (blob->magic() != kSecCodeMagicEntitlement) 134 note(0, "%s: unrecognized blob type (accepting blindly)", entitlements); 135 if (blob->length() != CFDataGetLength(data)) 136 fail("%s: invalid length in entitlement blob", entitlements); 137 CFDictionaryAddValue(parameters, kSecCodeSignerEntitlements, CFTempData(*blob)); 138 } 139 } else 140 fail("%s: cannot read entitlement data", entitlements); 141 } 142 143 if (dryrun) 144 CFDictionaryAddValue(parameters, kSecCodeSignerDryRun, kCFBooleanTrue); 145 146 MacOSError::check(SecCodeSignerCreate(parameters, flags, &signerRef)); 147} 148 149 150// 151// Sign a code object. 152// 153void sign(const char *target) 154{ 155 secdebug("codesign", "BEGIN SIGNING %s", target); 156 157 CFRef<SecStaticCodeRef> code = staticCodePath(target, architecture, bundleVersion); 158 159 // check previous signature (if any) and collect some data from it 160 CFRef<CFDictionaryRef> dict; 161 switch (OSStatus rc = SecCodeCopySigningInformation(code, 162 preserveMetadata ? SecCSFlags(kSecCSRequirementInformation|kSecCSInternalInformation) : kSecCSDefaultFlags, 163 &dict.aref())) { 164 case noErr: 165 if (CFDictionaryGetValue(dict, kSecCodeInfoIdentifier)) { // binary is signed 166 if (detached || detachedDb) 167 note(0, "%s: not disturbing embedded signature", target); 168 else if (force) 169 note(0, "%s: replacing existing signature", target); 170 else if (signer) 171 fail("%s: is already signed", target); 172 } 173 break; 174 default: 175 if (detached) 176 note(0, "%s: ignoring invalid embedded signature", target); 177 else if (force) 178 note(0, "%s: replacing invalid existing signature", target); 179 else if (signer) 180 fail("%s: is already signed", target); 181 break; 182 } 183 184 // add target-specific signing inputs, mostly carried from a prior signature 185 CFCopyRef<SecCodeSignerRef> currentSigner = signerRef; // the one we prepared during setup 186 187 // do the deed 188 ErrorCheck check; 189 check(SecCodeSignerAddSignatureWithErrors(currentSigner, code, kSecCSDefaultFlags, check)); 190 191 // collect some resulting information and deliver it to the user 192 SecCSFlags flags = kSecCSSigningInformation; 193 if (modifiedFiles) 194 flags |= kSecCSContentInformation; 195 MacOSError::check(SecCodeCopySigningInformation(code, flags, &dict.aref())); 196 note(1, "%s: signed %s [%s]", target, 197 cfString(CFStringRef(CFDictionaryGetValue(dict, kSecCodeInfoFormat))).c_str(), 198 cfString(CFStringRef(CFDictionaryGetValue(dict, kSecCodeInfoIdentifier))).c_str() 199 ); 200 201 CFRef<CFLocaleRef> userLocale = CFLocaleCopyCurrent(); 202 CFRef<CFDateFormatterRef> format = CFDateFormatterCreate(NULL, userLocale, 203 kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle); 204 CFDateRef softTime = CFDateRef(CFDictionaryGetValue(dict, kSecCodeInfoTime)); 205 CFDateRef hardTime = CFDateRef(CFDictionaryGetValue(dict, kSecCodeInfoTimestamp)); 206 if (hardTime) { 207 if (softTime) { 208 CFAbsoluteTime slop = abs(CFDateGetAbsoluteTime(softTime) - CFDateGetAbsoluteTime(hardTime)); 209 if (slop > timestampSlop) 210 fail("%s: timestamps differ by %g seconds - check your system clock", target, slop); 211 } else { 212 CFAbsoluteTime slop = abs(CFAbsoluteTimeGetCurrent() - CFDateGetAbsoluteTime(hardTime)); 213 if (slop > timestampSlop) 214 note(0, "%s: WARNING: local time diverges from timestamp by %g seconds - check your system clock", target, slop); 215 } 216 } 217 218 if (modifiedFiles) 219 writeFileList(CFArrayRef(CFDictionaryGetValue(dict, kSecCodeInfoChangedFiles)), modifiedFiles, "a"); 220} 221