]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_codesigning/lib/resources.cpp
Security-58286.20.16.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / lib / resources.cpp
index 5695800eabce99099c96aecb947cc1d414247952..25ddade7c61798bda60707492b63fc6a445658b8 100644 (file)
@@ -61,9 +61,8 @@ static string removeTrailingSlash(string path)
 // Construction and maintainance
 //
 ResourceBuilder::ResourceBuilder(const std::string &root, const std::string &relBase,
-       CFDictionaryRef rulesDict, CodeDirectory::HashAlgorithm hashType, bool strict, const MacOSErrorSet& toleratedErrors)
-       : mHashType(hashType),
-         mCheckUnreadable(strict && toleratedErrors.find(errSecCSSignatureNotVerifiable) == toleratedErrors.end()),
+       CFDictionaryRef rulesDict, bool strict, const MacOSErrorSet& toleratedErrors)
+       : mCheckUnreadable(strict && toleratedErrors.find(errSecCSSignatureNotVerifiable) == toleratedErrors.end()),
          mCheckUnknownType(strict && toleratedErrors.find(errSecCSResourceNotSupported) == toleratedErrors.end())
 {
        assert(!root.empty());
@@ -75,7 +74,7 @@ ResourceBuilder::ResourceBuilder(const std::string &root, const std::string &rel
                UnixError::throwMe();
        mRelBase = realroot;
        if (mRoot != mRelBase && mRelBase != mRoot + "/Contents")
-               MacOSError::throwMe(errSecCSInternalError);
+               MacOSError::throwMe(errSecCSBadBundleFormat);
        const char * paths[2] = { mRoot.c_str(), NULL };
        mFTS = fts_open((char * const *)paths, FTS_PHYSICAL | FTS_COMFOLLOW | FTS_NOCHDIR, NULL);
        if (!mFTS)
@@ -153,7 +152,7 @@ void ResourceBuilder::scan(Scanner next)
                }
                switch (ent->fts_info) {
                case FTS_F:
-                       secdebug("rdirenum", "file %s", ent->fts_path);
+                       secinfo("rdirenum", "file %s", ent->fts_path);
                        GKBIS_Num_files++;
                 
                        // These are checks for the gatekeeper collection
@@ -170,7 +169,7 @@ void ResourceBuilder::scan(Scanner next)
                        break;
                case FTS_SL:
                        // symlinks cannot ever be nested code, so quietly convert to resource file
-                       secdebug("rdirenum", "symlink %s", ent->fts_path);
+                       secinfo("rdirenum", "symlink %s", ent->fts_path);
                        GKBIS_Num_symlinks++;
 
                        if (strcasecmp(ent->fts_name, ds_store) == 0)
@@ -181,7 +180,7 @@ void ResourceBuilder::scan(Scanner next)
                                        next(ent, rule->flags & ~nested, string(relpath), rule);
                        break;
                case FTS_D:
-                       secdebug("rdirenum", "entering %s", ent->fts_path);
+                       secinfo("rdirenum", "entering %s", ent->fts_path);
                        GKBIS_Num_dirs++;
 
                        if (!first) {   // skip root directory (relpath invalid)
@@ -204,15 +203,15 @@ void ResourceBuilder::scan(Scanner next)
 
                        break;
                case FTS_DP:
-                       secdebug("rdirenum", "leaving %s", ent->fts_path);
+                       secinfo("rdirenum", "leaving %s", ent->fts_path);
                        break;
                case FTS_DNR:
-                       secdebug("rdirenum", "cannot read directory %s", ent->fts_path);
+                       secinfo("rdirenum", "cannot read directory %s", ent->fts_path);
                        if (mCheckUnreadable)
                                MacOSError::throwMe(errSecCSSignatureNotVerifiable);
                        break;
                default:
-                       secdebug("rdirenum", "type %d (errno %d): %s",
+                       secinfo("rdirenum", "type %d (errno %d): %s",
                                ent->fts_info, ent->fts_errno, ent->fts_path);
                        if (mCheckUnknownType)
                                MacOSError::throwMe(errSecCSResourceNotSupported);
@@ -249,21 +248,28 @@ bool ResourceBuilder::includes(string path) const
 ResourceBuilder::Rule *ResourceBuilder::findRule(string path) const
 {
        Rule *bestRule = NULL;
-       secdebug("rscan", "test %s", path.c_str());
+       secinfo("rscan", "test %s", path.c_str());
        for (Rules::const_iterator it = mRules.begin(); it != mRules.end(); ++it) {
                Rule *rule = *it;
-               secdebug("rscan", "try %s", rule->source.c_str());
+               secinfo("rscan", "try %s", rule->source.c_str());
                if (rule->match(path.c_str())) {
-                       secdebug("rscan", "match");
+                       secinfo("rscan", "match");
                        if (rule->flags & exclusion) {
-                               secdebug("rscan", "excluded");
+                               secinfo("rscan", "excluded");
                                return rule;
                        }
                        if (!bestRule || rule->weight > bestRule->weight)
                                bestRule = rule;
+
+
+#if TARGET_OS_WATCH
+/* rdar://problem/30517969 */
+                       if (bestRule && bestRule->weight == rule->weight && !(bestRule->flags & omitted) && (rule->flags & omitted))
+                               bestRule = rule;
+#endif
                }
        }
-       secdebug("rscan", "choosing %s (%d,0x%x)",
+       secinfo("rscan", "choosing %s (%d,0x%x)",
                bestRule ? bestRule->source.c_str() : "NOTHING",
                bestRule ? bestRule->weight : 0,
                bestRule ? bestRule->flags : 0);
@@ -274,11 +280,11 @@ ResourceBuilder::Rule *ResourceBuilder::findRule(string path) const
 //
 // Hash a file and return a CFDataRef with the hash
 //
-CFDataRef ResourceBuilder::hashFile(const char *path) const
+CFDataRef ResourceBuilder::hashFile(const char *path, CodeDirectory::HashAlgorithm type)
 {
        UnixPlusPlus::AutoFileDesc fd(path);
        fd.fcntl(F_NOCACHE, true);              // turn off page caching (one-pass)
-       MakeHash<ResourceBuilder> hasher(this);
+       RefPointer<DynamicHash> hasher(CodeDirectory::hashFor(type));
        hashFileData(fd, hasher.get());
        Hashing::Byte digest[hasher->digestLength()];
        hasher->finish(digest);
@@ -286,6 +292,41 @@ CFDataRef ResourceBuilder::hashFile(const char *path) const
 }
 
 
+//
+// Hash a file to multiple hash types and return a dictionary suitable to form a resource seal
+//
+CFMutableDictionaryRef ResourceBuilder::hashFile(const char *path, CodeDirectory::HashAlgorithms types, bool strictCheck)
+{
+       UnixPlusPlus::AutoFileDesc fd(path);
+       fd.fcntl(F_NOCACHE, true);              // turn off page caching (one-pass)
+       if (strictCheck)
+               if (fd.hasExtendedAttribute(XATTR_RESOURCEFORK_NAME) || fd.hasExtendedAttribute(XATTR_FINDERINFO_NAME))
+                       MacOSError::throwMe(errSecCSInvalidAssociatedFileData);
+       CFRef<CFMutableDictionaryRef> result = makeCFMutableDictionary();
+       CFMutableDictionaryRef resultRef = result;
+       CodeDirectory::multipleHashFileData(fd, 0, types, ^(CodeDirectory::HashAlgorithm type, Security::DynamicHash *hasher) {
+               size_t length = hasher->digestLength();
+               Hashing::Byte digest[length];
+               hasher->finish(digest);
+               CFDictionaryAddValue(resultRef, CFTempString(hashName(type)), CFTempData(digest, length));
+       });
+       return result.yield();
+}
+       
+       
+std::string ResourceBuilder::hashName(CodeDirectory::HashAlgorithm type)
+{
+       switch (type) {
+       case kSecCodeSignatureHashSHA1:
+               return "hash";
+       default:
+               char name[20];
+               snprintf(name, sizeof(name), "hash%d", int(type));
+               return name;
+       }
+}
+
+
 //
 // Regex matching objects
 //
@@ -294,7 +335,7 @@ ResourceBuilder::Rule::Rule(const std::string &pattern, unsigned w, uint32_t f)
 {
        if (::regcomp(this, pattern.c_str(), REG_EXTENDED | REG_NOSUB)) //@@@ REG_ICASE?
                MacOSError::throwMe(errSecCSResourceRulesInvalid);
-       secdebug("csresource", "%p rule %s added (weight %d, flags 0x%x)",
+       secinfo("csresource", "%p rule %s added (weight %d, flags 0x%x)",
                this, pattern.c_str(), w, f);
 }
 
@@ -321,7 +362,7 @@ std::string ResourceBuilder::escapeRE(const std::string &s)
        string r;
        for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
                char c = *it;
-               if (strchr("\\[]{}().+*?", c))
+               if (strchr("\\[]{}().+*?^$|", c))
                        r.push_back('\\');
                r.push_back(c);
        }
@@ -333,29 +374,43 @@ std::string ResourceBuilder::escapeRE(const std::string &s)
 // Resource Seals
 //
 ResourceSeal::ResourceSeal(CFTypeRef it)
-       : mDict(NULL), mHash(NULL), mRequirement(NULL), mLink(NULL), mFlags(0)
+       : mDict(NULL), mRequirement(NULL), mLink(NULL), mFlags(0)
 {
        if (it == NULL)
                MacOSError::throwMe(errSecCSResourcesInvalid);
-       if (CFGetTypeID(it) == CFDataGetTypeID()) {
-               mHash = CFDataRef(it);
-       } else {
-               int optional = 0;
+       if (CFGetTypeID(it) == CFDataGetTypeID())       // old-style form with just a hash
+               mDict.take(cfmake<CFDictionaryRef>("{hash=%O}", it));
+       else if (CFGetTypeID(it) == CFDictionaryGetTypeID())
                mDict = CFDictionaryRef(it);
-               bool err;
-               if (CFDictionaryGetValue(mDict, CFSTR("requirement")))
-                       err = !cfscan(mDict, "{requirement=%SO,?optional=%B}", &mRequirement, &optional);
-               else if (CFDictionaryGetValue(mDict, CFSTR("symlink")))
-                       err = !cfscan(mDict, "{symlink=%SO,?optional=%B}", &mLink, &optional);
-               else
-                       err = !cfscan(mDict, "{hash=%XO,?optional=%B}", &mHash, &optional);
-               if (err)
-                       MacOSError::throwMe(errSecCSResourcesInvalid);
-               if (optional)
-                       mFlags |= ResourceBuilder::optional;
-               if (mRequirement)
-                       mFlags |= ResourceBuilder::nested;
-       }
+       else
+               MacOSError::throwMe(errSecCSResourcesInvalid);
+
+       int optional = 0;
+       bool err;
+       if (CFDictionaryGetValue(mDict, CFSTR("requirement")))
+               err = !cfscan(mDict, "{requirement=%SO,?optional=%B}", &mRequirement, &optional);
+       else if (CFDictionaryGetValue(mDict, CFSTR("symlink")))
+               err = !cfscan(mDict, "{symlink=%SO,?optional=%B}", &mLink, &optional);
+       else
+               err = !cfscan(mDict, "{?optional=%B}", &optional);
+       if (err)
+               MacOSError::throwMe(errSecCSResourcesInvalid);
+       if (optional)
+               mFlags |= ResourceBuilder::optional;
+       if (mRequirement)
+               mFlags |= ResourceBuilder::nested;
+}
+       
+       
+const Hashing::Byte *ResourceSeal::hash(CodeDirectory::HashAlgorithm type) const
+{
+       std::string name = ResourceBuilder::hashName(type);
+       CFTypeRef hash = CFDictionaryGetValue(mDict, CFTempString(name));
+       if (hash == NULL)       // pre-agility fallback
+               hash = CFDictionaryGetValue(mDict, CFSTR("hash"));
+       if (hash == NULL || CFGetTypeID(hash) != CFDataGetTypeID())
+               MacOSError::throwMe(errSecCSResourcesInvalid);
+       return CFDataGetBytePtr(CFDataRef(hash));
 }