X-Git-Url: https://git.saurik.com/apple/libsecurity_codesigning.git/blobdiff_plain/6aae018b5d43c30038cfa4003e5d4bcc81f134cf..HEAD:/lib/SecStaticCode.cpp diff --git a/lib/SecStaticCode.cpp b/lib/SecStaticCode.cpp index a099dfb..7cb5a17 100644 --- a/lib/SecStaticCode.cpp +++ b/lib/SecStaticCode.cpp @@ -26,7 +26,9 @@ // #include "cs.h" #include "StaticCode.h" +#include #include +#include using namespace CodeSigning; @@ -50,7 +52,38 @@ OSStatus SecStaticCodeCreateWithPath(CFURLRef path, SecCSFlags flags, SecStaticC BEGIN_CSAPI checkFlags(flags); - Required(staticCodeRef) = (new SecStaticCode(DiskRep::bestGuess(cfString(path).c_str())))->handle(); + CodeSigning::Required(staticCodeRef) = (new SecStaticCode(DiskRep::bestGuess(cfString(path).c_str())))->handle(); + + END_CSAPI +} + +const CFStringRef kSecCodeAttributeArchitecture = CFSTR("architecture"); +const CFStringRef kSecCodeAttributeSubarchitecture =CFSTR("subarchitecture"); +const CFStringRef kSecCodeAttributeBundleVersion = CFSTR("bundleversion"); + +OSStatus SecStaticCodeCreateWithPathAndAttributes(CFURLRef path, SecCSFlags flags, CFDictionaryRef attributes, + SecStaticCodeRef *staticCodeRef) +{ + BEGIN_CSAPI + + checkFlags(flags); + DiskRep::Context ctx; + std::string version; // holds memory placed into ctx + if (attributes) { + std::string archName; + int archNumber, subarchNumber; + if (cfscan(attributes, "{%O=%s}", kSecCodeAttributeArchitecture, &archName)) { + ctx.arch = Architecture(archName.c_str()); + } else if (cfscan(attributes, "{%O=%d,%O=%d}", + kSecCodeAttributeArchitecture, &archNumber, kSecCodeAttributeSubarchitecture, &subarchNumber)) + ctx.arch = Architecture(archNumber, subarchNumber); + else if (cfscan(attributes, "{%O=%d}", kSecCodeAttributeArchitecture, &archNumber)) + ctx.arch = Architecture(archNumber); + if (cfscan(attributes, "{%O=%s}", kSecCodeAttributeBundleVersion, &version)) + ctx.version = version.c_str(); + } + + CodeSigning::Required(staticCodeRef) = (new SecStaticCode(DiskRep::bestGuess(cfString(path).c_str(), &ctx)))->handle(); END_CSAPI } @@ -59,6 +92,85 @@ OSStatus SecStaticCodeCreateWithPath(CFURLRef path, SecCSFlags flags, SecStaticC // // Check static validity of a StaticCode // +static void validate(SecStaticCode *code, const SecRequirement *req, SecCSFlags flags); +static void validateNested(string location, const SecRequirement *req, SecCSFlags flags, string exclude = "/"); + +static void validate(SecStaticCode *code, const SecRequirement *req, SecCSFlags flags) +{ + try { + code->validateNonResourceComponents(); // also validates the CodeDirectory + if (!(flags & kSecCSDoNotValidateExecutable)) + code->validateExecutable(); + if (!(flags & kSecCSDoNotValidateResources)) + code->validateResources(); + if (req) + code->validateRequirement(req->requirement(), errSecCSReqFailed); + if (flags & kSecCSCheckNestedCode) + if (CFURLRef baseUrl = code->resourceBase()) { + // CFBundle has no orderly enumerator of these things, so this is somewhat ad-hoc. + // (It should be augmented by information in ResourceDirectory.) + string base = cfString(baseUrl) + "/"; + validateNested(base + "Frameworks", req, flags); + validateNested(base + "SharedFrameworks", req, flags); + validateNested(base + "PlugIns", req, flags); + validateNested(base + "Plug-ins", req, flags); + validateNested(base + "XPCServices", req, flags); + validateNested(base + "MacOS", req, flags, code->mainExecutablePath()); // helpers + } + } catch (CSError &err) { + if (Universal *fat = code->diskRep()->mainExecutableImage()) // Mach-O + if (MachO *mach = fat->architecture()) { + err.augment(kSecCFErrorArchitecture, CFTempString(mach->architecture().displayName())); + delete mach; + } + throw; + } catch (const MacOSError &err) { + // add architecture information if we can get it + if (Universal *fat = code->diskRep()->mainExecutableImage()) + if (MachO *mach = fat->architecture()) { + CFTempString arch(mach->architecture().displayName()); + delete mach; + CSError::throwMe(err.error, kSecCFErrorArchitecture, arch); + } + // else just pass it on + throw; + } +} + +static void validateNested(string location, const SecRequirement *req, SecCSFlags flags, string exclude) +{ + DIR *dir = opendir(location.c_str()); + if (dir == 0) { + if (errno == ENOENT) // nothing there (okay) + return; + UnixError::throwMe(); + } + while (struct dirent *dp = readdir(dir)) { + switch (dp->d_type) { + case DT_REG: + case DT_LNK: + case DT_DIR: + break; + default: + continue; + } + if (dp->d_name[0] == '.') + continue; + string path = location + "/" + dp->d_name; + if (path == exclude) // main executable; skip + continue; + try { + SecPointer code = new SecStaticCode(DiskRep::bestGuess(path)); + validate(code, req, flags); + } catch (CSError &err) { + err.augment(kSecCFErrorPath, CFTempURL(path)); + throw; + } + } + closedir(dir); +} + + OSStatus SecStaticCodeCheckValidity(SecStaticCodeRef staticCodeRef, SecCSFlags flags, SecRequirementRef requirementRef) { @@ -74,17 +186,19 @@ OSStatus SecStaticCodeCheckValidityWithErrors(SecStaticCodeRef staticCodeRef, Se kSecCSCheckAllArchitectures | kSecCSDoNotValidateExecutable | kSecCSDoNotValidateResources - | kSecCSConsiderExpiration); + | kSecCSConsiderExpiration + | kSecCSEnforceRevocationChecks + | kSecCSCheckNestedCode); SecPointer code = SecStaticCode::requiredStatic(staticCodeRef); + const SecRequirement *req = SecRequirement::optional(requirementRef); DTRACK(CODESIGN_EVAL_STATIC, code, (char*)code->mainExecutablePath().c_str()); - code->validateDirectory(); - if (!(flags & kSecCSDoNotValidateExecutable)) - code->validateExecutable(); - if (!(flags & kSecCSDoNotValidateResources)) - code->validateResources(); - if (const SecRequirement *req = SecRequirement::optional(requirementRef)) - code->validateRequirements(req->requirement(), errSecCSReqFailed); + if (flags & kSecCSCheckAllArchitectures) { + SecStaticCode::AllArchitectures archs(code); + while (SecPointer scode = archs()) + validate(scode, req, flags); + } else + validate(code, req, flags); END_CSAPI_ERRORS } @@ -108,7 +222,7 @@ OSStatus SecCodeCopyPath(SecStaticCodeRef staticCodeRef, SecCSFlags flags, CFURL checkFlags(flags); SecPointer staticCode = SecStaticCode::requiredStatic(staticCodeRef); - Required(path) = staticCode->canonicalPath(); + CodeSigning::Required(path) = staticCode->canonicalPath(); END_CSAPI } @@ -125,7 +239,7 @@ OSStatus SecCodeCopyDesignatedRequirement(SecStaticCodeRef staticCodeRef, SecCSF checkFlags(flags); const Requirement *req = SecStaticCode::requiredStatic(staticCodeRef)->designatedRequirement(); - Required(requirementRef) = (new SecRequirement(req))->handle(); + CodeSigning::Required(requirementRef) = (new SecRequirement(req))->handle(); END_CSAPI } @@ -142,7 +256,7 @@ OSStatus SecCodeCopyInternalRequirement(SecStaticCodeRef staticCodeRef, SecRequi checkFlags(flags); const Requirement *req = SecStaticCode::requiredStatic(staticCodeRef)->internalRequirement(type); - Required(requirementRef) = req ? (new SecRequirement(req))->handle() : NULL; + CodeSigning::Required(requirementRef) = req ? (new SecRequirement(req))->handle() : NULL; END_CSAPI }