Skip to content

Commit

Permalink
Fix wildcard application-identifier in entitlement
Browse files Browse the repository at this point in the history
The provisioning profile defines a list of supported entitlements which may
include wildcard identifiers. The actual application entitlement should not
contain any wildcards. This results in bugs such as broken file import on
iOS 14.

This patch only fixes wildcards in application-identifier. It does not fix
any other keys. It does not support wildcards except '*'.

As part of the change, the feature to remove get-task-allow is also moved to
unify the entitlement modification code.
  • Loading branch information
osy86 authored and DanTheMan827 committed Feb 18, 2021
1 parent 70f9ac6 commit bf84b96
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 51 deletions.
28 changes: 20 additions & 8 deletions AppSigner/MainView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -854,16 +854,32 @@ class MainView: NSView, URLSessionDataDelegate, URLSessionDelegate, URLSessionDo
}
}

let bundleID = getPlistKey(appBundleInfoPlist, keyName: "CFBundleIdentifier")

//MARK: Generate entitlements.plist
if provisioningFile != nil || useAppBundleProfile {
setStatus("Parsing entitlements")

if let profile = ProvisioningProfile(filename: useAppBundleProfile ? appBundleProvisioningFilePath : provisioningFile!, skipGetTaskAllow: shouldSkipGetTaskAllow){
if let entitlements = profile.getEntitlementsPlist(tempFolder) {
if var profile = ProvisioningProfile(filename: useAppBundleProfile ? appBundleProvisioningFilePath : provisioningFile!){
if shouldSkipGetTaskAllow {
profile.removeGetTaskAllow()
}
let isWildcard = profile.appID == "*" // TODO: support com.example.* wildcard
if !isWildcard && (newApplicationID != "" && newApplicationID != profile.appID) {
setStatus("Unable to change App ID to \(newApplicationID), provisioning profile won't allow it")
cleanup(tempFolder); return
} else if isWildcard {
if newApplicationID != "" {
profile.update(trueAppID: newApplicationID)
} else if let existingBundleID = bundleID {
profile.update(trueAppID: existingBundleID)
}
}
if let entitlements = profile.getEntitlementsPlist() {
Log.write("–––––––––––––––––––––––\n\(entitlements)")
Log.write("–––––––––––––––––––––––")
do {
try entitlements.write(toFile: entitlementsPlist, atomically: false, encoding: String.Encoding.utf8.rawValue)
try entitlements.write(toFile: entitlementsPlist, atomically: false, encoding: .utf8)
setStatus("Saved entitlements to \(entitlementsPlist)")
} catch let error as NSError {
setStatus("Error writing entitlements.plist, \(error.localizedDescription)")
Expand All @@ -872,10 +888,6 @@ class MainView: NSView, URLSessionDataDelegate, URLSessionDelegate, URLSessionDo
setStatus("Unable to read entitlements from provisioning profile")
warnings += 1
}
if profile.appID != "*" && (newApplicationID != "" && newApplicationID != profile.appID) {
setStatus("Unable to change App ID to \(newApplicationID), provisioning profile won't allow it")
cleanup(tempFolder); return
}
} else {
setStatus("Unable to parse provisioning profile, it may be corrupt")
warnings += 1
Expand All @@ -891,7 +903,7 @@ class MainView: NSView, URLSessionDataDelegate, URLSessionDelegate, URLSessionDo
//MARK: Change Application ID
if newApplicationID != "" {

if let oldAppID = getPlistKey(appBundleInfoPlist, keyName: "CFBundleIdentifier") {
if let oldAppID = bundleID {
func changeAppexID(_ appexFile: String){
guard allowRecursiveSearchAt(appexFile.stringByDeletingLastPathComponent) else {
return
Expand Down
76 changes: 33 additions & 43 deletions ProvisioningProfile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ struct ProvisioningProfile {
expires: Date,
appID: String,
teamID: String,
rawXML: String,
entitlements: AnyObject?
entitlements: [String : AnyObject]
fileprivate let delegate = NSApplication.shared.delegate as! AppDelegate

static func getProfiles() -> [ProvisioningProfile] {
Expand Down Expand Up @@ -55,49 +54,35 @@ struct ProvisioningProfile {
return newProfiles;
}

init?(filename: String, skipGetTaskAllow: Bool = false){
init?(filename: String){
let securityArgs = ["cms","-D","-i", filename]

let taskOutput = Process().execute("/usr/bin/security", workingDirectory: nil, arguments: securityArgs)
let rawXML: String
if taskOutput.status == 0 {
if let xmlIndex = taskOutput.output.range(of: "<?xml") {
self.rawXML = taskOutput.output.substring(from: xmlIndex.lowerBound)
rawXML = taskOutput.output.substring(from: xmlIndex.lowerBound)
} else {
Log.write("Unable to find xml start tag in profile")
self.rawXML = taskOutput.output
}

if skipGetTaskAllow {
Log.write("Skipping get-task-allow entitlement...");

if let results = try? PropertyListSerialization.propertyList(from: self.rawXML.data(using: String.Encoding.utf8)!, options: PropertyListSerialization.MutabilityOptions(), format: nil) {
var resultsdict = results as! Dictionary<String, AnyObject>
var entitlements = resultsdict["Entitlements"] as! Dictionary<String, AnyObject>
entitlements.removeValue(forKey: "get-task-allow")
resultsdict["Entitlements"] = entitlements as AnyObject

let data = PropertyListSerialization.dataFromPropertyList(resultsdict, format: PropertyListSerialization.PropertyListFormat.xml, errorDescription: nil)!
self.rawXML = String(data: data, encoding: .utf8)!
Log.write("Skipped get-task-allow entitlement!");
}
rawXML = taskOutput.output
}



if let results = try? PropertyListSerialization.propertyList(from: self.rawXML.data(using: String.Encoding.utf8)!, options: PropertyListSerialization.MutabilityOptions(), format: nil) {
if let expirationDate = (results as AnyObject).value(forKey: "ExpirationDate") as? Date,
let creationDate = (results as AnyObject).value(forKey: "CreationDate") as? Date,
let name = (results as AnyObject).value(forKey: "Name") as? String,
let entitlements = (results as AnyObject).value(forKey: "Entitlements"),
let applicationIdentifier = (entitlements as AnyObject).value(forKey: "application-identifier") as? String,
if let results = try? PropertyListSerialization.propertyList(from: rawXML.data(using: String.Encoding.utf8)!, options: .mutableContainers, format: nil) as? [String : AnyObject] {
if let expirationDate = results["ExpirationDate"] as? Date,
let creationDate = results["CreationDate"] as? Date,
let name = results["Name"] as? String,
let entitlements = results["Entitlements"] as? [String : AnyObject],
let applicationIdentifier = entitlements["application-identifier"] as? String,
let periodIndex = applicationIdentifier.firstIndex(of: ".") {
self.filename = filename
self.expires = expirationDate
self.created = creationDate
self.appID = applicationIdentifier.substring(from: applicationIdentifier.index(periodIndex, offsetBy: 1))
self.teamID = applicationIdentifier.substring(to: periodIndex)
self.name = name
self.entitlements = entitlements as AnyObject?
self.entitlements = entitlements
} else {
Log.write("Error processing \(filename.lastPathComponent)")
return nil
Expand All @@ -112,22 +97,27 @@ struct ProvisioningProfile {
}
}

func getEntitlementsPlist(_ tempFolder: String) -> NSString? {
let mobileProvisionPlist = tempFolder.stringByAppendingPathComponent("mobileprovision.plist")
do {
try self.rawXML.write(toFile: mobileProvisionPlist, atomically: false, encoding: String.Encoding.utf8)
let plistBuddy = Process().execute("/usr/libexec/PlistBuddy", workingDirectory: nil, arguments: ["-c", "Print :Entitlements",mobileProvisionPlist, "-x"])
if plistBuddy.status == 0 {
return plistBuddy.output as NSString?
} else {
Log.write("PlistBuddy Failed")
Log.write(plistBuddy.output)
return nil
}
} catch let error as NSError {
Log.write("Error writing mobileprovision.plist")
Log.write(error.localizedDescription)
return nil
mutating func removeGetTaskAllow() {
if let _ = entitlements.removeValue(forKey: "get-task-allow") {
Log.write("Skipped get-task-allow entitlement!");
} else {
Log.write("get-task-allow entitlement not found!");
}
}

mutating func update(trueAppID: String) {
guard let oldIdentifier = entitlements["application-identifier"] as? String else {
Log.write("Error reading application-identifier")
return
}
let newIdentifier = teamID + "." + trueAppID
entitlements["application-identifier"] = newIdentifier as AnyObject
Log.write("Updated application-identifier from '\(oldIdentifier)' to '\(newIdentifier)'")
// TODO: update any other wildcard entitlements
}

func getEntitlementsPlist() -> String? {
let data = PropertyListSerialization.dataFromPropertyList(entitlements, format: PropertyListSerialization.PropertyListFormat.xml, errorDescription: nil)!
return String(data: data, encoding: .utf8)
}
}

0 comments on commit bf84b96

Please sign in to comment.