1/* 2 * Copyright (c) 2002-2004 Apple Computer, 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// TrustedApplication.cpp 26// 27#include <security_keychain/TrustedApplication.h> 28#include <security_keychain/ACL.h> 29#include <security_utilities/osxcode.h> 30#include <security_utilities/trackingallocator.h> 31#include <security_cdsa_utilities/acl_codesigning.h> 32#include <sys/syslimits.h> 33#include <memory> 34 35using namespace KeychainCore; 36 37 38// 39// Create a TrustedApplication from a code-signing ACL subject. 40// Throws ACL::ParseError if the subject is unexpected. 41// 42TrustedApplication::TrustedApplication(const TypedList &subject) 43{ 44 try { 45 CodeSignatureAclSubject::Maker maker; 46 mForm = maker.make(subject); 47 secdebug("trustedapp", "%p created from list form", this); 48 IFDUMPING("codesign", mForm->AclSubject::dump("STApp created from list")); 49 } catch (...) { 50 throw ACL::ParseError(); 51 } 52} 53 54 55// 56// Create a TrustedApplication from a path-to-object-on-disk 57// 58TrustedApplication::TrustedApplication(const std::string &path) 59{ 60 RefPointer<OSXCode> code(OSXCode::at(path)); 61 mForm = new CodeSignatureAclSubject(OSXVerifier(code)); 62 secdebug("trustedapp", "%p created from path %s", this, path.c_str()); 63 IFDUMPING("codesign", mForm->AclSubject::dump("STApp created from path")); 64} 65 66 67// 68// Create a TrustedApplication for the calling process 69// 70TrustedApplication::TrustedApplication() 71{ 72 //@@@@ should use CS's idea of "self" 73 RefPointer<OSXCode> me(OSXCode::main()); 74 mForm = new CodeSignatureAclSubject(OSXVerifier(me)); 75 secdebug("trustedapp", "%p created from self", this); 76 IFDUMPING("codesign", mForm->AclSubject::dump("STApp created from self")); 77} 78 79 80// 81// Create a TrustedApplication from a SecRequirementRef. 82// Note that the path argument is only stored for documentation; 83// it is NOT used to denote anything on disk. 84// 85TrustedApplication::TrustedApplication(const std::string &path, SecRequirementRef reqRef) 86{ 87 CFRef<CFDataRef> reqData; 88 MacOSError::check(SecRequirementCopyData(reqRef, kSecCSDefaultFlags, &reqData.aref())); 89 mForm = new CodeSignatureAclSubject(NULL, path); 90 mForm->add((const BlobCore *)CFDataGetBytePtr(reqData)); 91 secdebug("trustedapp", "%p created from path %s and requirement %p", 92 this, path.c_str(), reqRef); 93 IFDUMPING("codesign", mForm->debugDump()); 94} 95 96 97TrustedApplication::~TrustedApplication() 98{ /* virtual */ } 99 100 101// 102// Convert from/to external data form. 103// 104// Since a TrustedApplication's data is essentially a CodeSignatureAclSubject, 105// we just use the subject's externalizer to produce the data. That requires us 106// to use the somewhat idiosyncratic linearizer used by CSSM ACL subjects, but 107// that's a small price to pay for consistency. 108// 109TrustedApplication::TrustedApplication(CFDataRef external) 110{ 111 AclSubject::Reader pubReader(CFDataGetBytePtr(external)), privReader; 112 mForm = CodeSignatureAclSubject::Maker().make(0, pubReader, privReader); 113} 114 115CFDataRef TrustedApplication::externalForm() const 116{ 117 AclSubject::Writer::Counter pubCounter, privCounter; 118 mForm->exportBlob(pubCounter, privCounter); 119 if (privCounter > 0) // private exported data - format violation 120 CssmError::throwMe(CSSMERR_CSSM_INTERNAL_ERROR); 121 CFRef<CFMutableDataRef> data = CFDataCreateMutable(NULL, pubCounter); 122 CFDataSetLength(data, pubCounter); 123 if (CFDataGetLength(data) < CFIndex(pubCounter)) 124 CFError::throwMe(); 125 AclSubject::Writer pubWriter(CFDataGetMutableBytePtr(data)), privWriter; 126 mForm->exportBlob(pubWriter, privWriter); 127 return data.yield(); 128} 129 130void TrustedApplication::data(CFDataRef data) 131{ 132 const char *p = (const char *)CFDataGetBytePtr(data); 133 const std::string path(p, p + CFDataGetLength(data)); 134 RefPointer<OSXCode> code(OSXCode::at(path)); 135 mForm = new CodeSignatureAclSubject(OSXVerifier(code)); 136} 137 138// 139// Direct verification interface. 140// If path == NULL, we verify against the running code itself. 141// 142bool TrustedApplication::verifyToDisk(const char *path) 143{ 144 if (SecRequirementRef requirement = mForm->requirement()) { 145 secdebug("trustedapp", "%p validating requirement against path %s", this, path); 146 CFRef<SecStaticCodeRef> ondisk; 147 if (path) 148 MacOSError::check(SecStaticCodeCreateWithPath(CFTempURL(path), 149 kSecCSDefaultFlags, &ondisk.aref())); 150 else 151 MacOSError::check(SecCodeCopySelf(kSecCSDefaultFlags, (SecCodeRef *)&ondisk.aref())); 152 return SecStaticCodeCheckValidity(ondisk, kSecCSDefaultFlags, requirement) == errSecSuccess; 153 } else { 154 secdebug("trustedapp", "%p validating hash against path %s", this, path); 155 RefPointer<OSXCode> code = path ? OSXCode::at(path) : OSXCode::main(); 156 SHA1::Digest ondiskDigest; 157 OSXVerifier::makeLegacyHash(code, ondiskDigest); 158 return memcmp(ondiskDigest, mForm->legacyHash(), sizeof(ondiskDigest)) == 0; 159 } 160} 161 162 163// 164// Produce a TypedList representing a code-signing ACL subject 165// for this application. 166// Memory is allocated from the allocator given, and belongs to 167// the caller. 168// 169CssmList TrustedApplication::makeSubject(Allocator &allocator) 170{ 171 return mForm->toList(allocator); 172} 173 174 175// 176// On a completely different note... 177// Read a simple text file from disk and cache the lines in a set. 178// This is used during re-prebinding to cut down on the number of 179// equivalency records being generated. 180// This feature is otherwise completely unconnected to anything else here. 181// 182PathDatabase::PathDatabase(const char *path) 183{ 184 if (FILE *f = fopen(path, "r")) { 185 mQualifyAll = false; 186 char path[PATH_MAX+1]; 187 while (fgets(path, sizeof(path), f)) { 188 path[strlen(path)-1] = '\0'; // strip NL 189 mPaths.insert(path); 190 } 191 fclose(f); 192 secdebug("equivdb", "read %ld paths from %s", mPaths.size(), path); 193 } else { 194 mQualifyAll = true; 195 secdebug("equivdb", "cannot open %s, will qualify all application paths", path); 196 } 197} 198 199 200bool PathDatabase::lookup(const string &inPath) 201{ 202 string path = inPath; 203 string::size_type lastSlash = path.rfind('/'); 204 string::size_type bundleCore = path.find("/Contents/MacOS/"); 205 if (lastSlash != string::npos && bundleCore != string::npos) 206 if (bundleCore + 15 == lastSlash) 207 path = path.substr(0, bundleCore); // @@@ path is being modified here so it can't be const. 208 return mPaths.find(path) != mPaths.end(); 209} 210