1/* 2 * Copyright (c) 2000-2001,2011,2013-2014 Apple Inc. All Rights Reserved. 3 * 4 * The contents of this file constitute Original Code as defined in and are 5 * subject to the Apple Public Source License Version 1.2 (the 'License'). 6 * You may not use this file except in compliance with the License. Please obtain 7 * a copy of the License at http://www.apple.com/publicsource and read it before 8 * using this file. 9 * 10 * This Original Code and all software distributed under the License are 11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS 12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT 13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the 15 * specific language governing rights and limitations under the License. 16 */ 17 18 19// 20// osxsigner - MacOS X's standard code signing algorithm. 21// 22#include <security_cdsa_utilities/osxverifier.h> 23#include <security_utilities/unix++.h> 24#include <security_utilities/hashing.h> 25#include <security_utilities/memutils.h> 26#include <security_utilities/debugging.h> 27#include <security_codesigning/requirement.h> 28#include <security_codesigning/reqdumper.h> // debug only 29 30 31using namespace CodeSigning; 32 33 34namespace Security { 35 36 37// 38// Create a Verifier from a code object. 39// 40// This does not add any auxiliary information blobs. You can do that 41// by calling add() after construction, of course. 42// 43OSXVerifier::OSXVerifier(OSXCode *code) 44{ 45 mPath = code->canonicalPath(); 46 secdebug("codesign", "building verifier for %s", mPath.c_str()); 47 48 // build new-style verifier 49 CFRef<SecStaticCodeRef> staticCode = code->codeRef(); 50 switch (OSStatus rc = SecCodeCopyDesignatedRequirement(staticCode, 51 kSecCSDefaultFlags, &mRequirement.aref())) { 52 case errSecSuccess: 53 secdebug("codesign", " is signed; canonical requirement loaded"); 54 break; 55 case errSecCSUnsigned: 56 secdebug("codesign", " is unsigned; no requirement"); 57 break; 58 default: 59 MacOSError::throwMe(rc); 60 } 61 62 // build old-style verifier 63 makeLegacyHash(code, mLegacyHash); 64 secdebug("codesign", " hash generated"); 65} 66 67 68// 69// Create a Verifier from hash, path, and requirement. 70// Again, this has no auxiliary data when constructed. 71// 72OSXVerifier::OSXVerifier(const SHA1::Byte *hash, const std::string &path) 73 : mPath(path) 74{ 75 secdebug("codesign", "building verifier from hash %p and path=%s", hash, path.c_str()); 76 if (hash) 77 memcpy(mLegacyHash, hash, sizeof(mLegacyHash)); 78 else 79 memset(mLegacyHash, 0, sizeof(mLegacyHash)); 80} 81 82 83OSXVerifier::~OSXVerifier() 84{ 85 secdebug("codesign", "%p verifier destroyed", this); 86} 87 88 89// 90// Add an auxiliary comment blob. 91// Note that we only allow one auxiliary blob for each magic number. 92// 93void OSXVerifier::add(const BlobCore *blob) 94{ 95 if (blob->is<Requirement>()) { 96#if defined(NDEBUG) 97 secdebug("codesign", "%p verifier adds requirement", this); 98#else 99 secdebug("codesign", "%p verifier adds requirement %s", this, 100 Dumper::dump(Requirement::specific(blob), true).c_str()); 101#endif //NDEBUG 102 MacOSError::check(SecRequirementCreateWithData(CFTempData(*blob), 103 kSecCSDefaultFlags, &mRequirement.aref())); 104 } else { 105 secdebug("codesign", "%p verifier adds blob (0x%x,%zd)", 106 this, blob->magic(), blob->length()); 107 BlobCore * &slot = mAuxiliary[blob->magic()]; 108 if (slot) 109 ::free(slot); 110 slot = blob->clone(); 111 } 112} 113 114 115// 116// Find a comment blob, by magic number 117// 118const BlobCore *OSXVerifier::find(BlobCore::Magic magic) 119{ 120 AuxMap::const_iterator it = mAuxiliary.find(magic); 121 return (it == mAuxiliary.end()) ? NULL : it->second; 122} 123 124 125void OSXVerifier::makeLegacyHash(OSXCode *code, SHA1::Digest digest) 126{ 127 secdebug("codesign", "calculating legacy hash for %s", code->canonicalPath().c_str()); 128 UnixPlusPlus::AutoFileDesc fd(code->executablePath(), O_RDONLY); 129 char buffer[legacyHashLimit]; 130 size_t size = fd.read(buffer, legacyHashLimit); 131 SHA1 hash; 132 hash(buffer, size); 133 hash.finish(digest); 134} 135 136 137// 138// The AuxMap helper class provides a map-to-Blob-pointers with automatic memory management. 139// 140OSXVerifier::AuxMap::AuxMap(const OSXVerifier::AuxMap &src) 141{ 142 for (const_iterator it = src.begin(); it != src.end(); it++) 143 this->insert(*it); 144} 145 146OSXVerifier::AuxMap::~AuxMap() 147{ 148 for (const_iterator it = this->begin(); it != this->end(); ++it) 149 ::free(it->second); 150} 151 152 153#if DEBUGDUMP 154 155void OSXVerifier::dump() const 156{ 157 static const SHA1::Digest nullDigest = { 0 }; 158 if (!memcmp(mLegacyHash, nullDigest, sizeof(mLegacyHash))) { 159 Debug::dump("(no hash)"); 160 } else { 161 Debug::dump("oldHash="); 162 Debug::dumpData(mLegacyHash, sizeof(mLegacyHash)); 163 } 164 if (mRequirement) { 165 CFRef<CFDataRef> reqData; 166 if (!SecRequirementCopyData(mRequirement, 0, &reqData.aref())) { 167 Debug::dump(" Requirement =>"); 168 ((const Requirement *)CFDataGetBytePtr(reqData))->dump(); 169 } 170 } else { 171 Debug::dump(" NO REQ"); 172 } 173} 174 175#endif //DEBUGDUMP 176 177} // end namespace Security 178