CodeSignIdentity GetBestMatch (List<CodeSignIdentity> pairs, CodeSignIdentity identity) { var matches = new List<CodeSignIdentity> (); int bestMatchLength = 0; int matchLength; // find matching provisioning profiles with compatible appid, keeping only those with the longest matching (wildcard) ids Log.LogMessage (MessageImportance.Low, MSBStrings.M0134); foreach (var pair in pairs) { var appid = ConstructValidAppId (pair.Profile, identity.BundleId, out matchLength); if (appid != null) { if (matchLength >= bestMatchLength) { if (matchLength > bestMatchLength) { bestMatchLength = matchLength; foreach (var previousMatch in matches) Log.LogMessage (MessageImportance.Low, MSBStrings.M0135, previousMatch.AppId, appid); matches.Clear (); } var match = identity.Clone (); match.SigningKey = pair.SigningKey; match.Profile = pair.Profile; match.AppId = appid; matches.Add (match); } else { string currentMatches = ""; foreach (var match in matches) currentMatches += $"{match}; "; Log.LogMessage (MessageImportance.Low, MSBStrings.M0136, appid, currentMatches); } } } if (matches.Count == 0) { Log.LogWarning (null, null, null, AppManifest, 0, 0, 0, 0, MSBStrings.W0137); return identity; } if (matches.Count > 1) { var spaces = new string (' ', 3); Log.LogMessage (MessageImportance.Normal, MSBStrings.M0138); matches.Sort (new SigningIdentityComparer ()); for (int i = 0; i < matches.Count; i++) { Log.LogMessage (MessageImportance.Normal, "{0,3}. Provisioning Profile: \"{1}\" ({2})", i + 1, matches[i].Profile.Name, matches[i].Profile.Uuid); if (matches[i].SigningKey != null) Log.LogMessage (MessageImportance.Normal, "{0} Signing Identity: \"{1}\"", spaces, SecKeychain.GetCertificateCommonName (matches[i].SigningKey)); } } return matches[0]; }
public override bool Execute() { PDictionary plist; IList <MobileProvision> profiles; IList <X509Certificate2> certs; List <CodeSignIdentity> pairs; var type = GetProvisioningDistributionType(); var platform = MobileProvisionPlatform.iOS; var identity = new CodeSignIdentity(); hotRestartClient = new HotRestartClient(); try { plist = PDictionary.FromFile(AppManifest); } catch (Exception ex) { Log.LogError(null, null, null, AppManifest, 0, 0, 0, 0, "Error loading '{0}': {1}", AppManifest, ex.Message); return(false); } identity.BundleId = plist.GetCFBundleIdentifier(); if (string.IsNullOrEmpty(identity.BundleId)) { if (GenerateApplicationManifest && !string.IsNullOrEmpty(ApplicationId)) { identity.BundleId = ApplicationId; } else { Log.LogError(null, null, null, AppManifest, 0, 0, 0, 0, "{0} does not define CFBundleIdentifier", AppManifest); return(false); } } DetectedBundleId = identity.BundleId; var appDisplayName = plist.GetCFBundleDisplayName(); if (string.IsNullOrEmpty(appDisplayName)) { if (GenerateApplicationManifest && !string.IsNullOrEmpty(ApplicationTitle)) { appDisplayName = ApplicationTitle; } } DetectedAppDisplayName = appDisplayName; if (!TryGetSigningCertificates(out certs, false)) { return(false); } Log.LogMessage(MessageImportance.Low, "Available certificates:"); foreach (var cert in certs) { Log.LogMessage(MessageImportance.Low, " {0}", GetCertificateCommonName(cert)); } if (!IsAutoCodeSignProfile(ProvisioningProfile)) { identity.Profile = MobileProvisionIndex.GetMobileProvision(platform, ProvisioningProfile); if (identity.Profile == null) { Log.LogError("The specified " + PlatformName + " provisioning profile '{0}' could not be found. Please enable Automatic Provisioning from the iOS Bundle Signing page.", ProvisioningProfile); return(false); } var profile = identity.Profile; // capture ref for lambda if (certs.Count > 0) { identity.SigningKey = certs.FirstOrDefault(c => profile.DeveloperCertificates.Any(p => p.Thumbprint == c.Thumbprint)); if (identity.SigningKey == null) { Log.LogError("No " + PlatformName + " signing identities match the specified provisioning profile '{0}'.", ProvisioningProfile); return(false); } } identity.AppId = ConstructValidAppId(identity.Profile, identity.BundleId); if (identity.AppId == null) { Log.LogError(null, null, null, AppManifest, 0, 0, 0, 0, "Project bundle identifier '{0}' does not match specified provisioning profile '{1}'. Please enable Automatic Provisioning from the iOS Bundle Signing page.", identity.BundleId, ProvisioningProfile); return(false); } if (identity.SigningKey != null) { codesignCommonName = GetCertificateCommonName(identity.SigningKey); DetectedCodeSigningPath = Path.Combine(CertificatesPath, $"{identity.SigningKey.SerialNumber}.p12"); } provisioningProfileName = identity.Profile.Name; DetectedAppId = identity.AppId; DetectedProvisioningProfileId = identity.Profile.Uuid; DetectedProvisioningProfilePath = Path.Combine(ProfilesPath, $"{DetectedProvisioningProfileId}.mobileprovision"); ReportDetectedCodesignInfo(); return(!Log.HasLoggedErrors); } if ((profiles = GetProvisioningProfiles(platform, type, identity, certs)) == null) { return(false); } if ((pairs = GetCodeSignIdentityPairs(profiles, certs)) == null) { return(false); } identity = GetBestMatch(pairs, identity); if (identity.Profile != null && identity.AppId != null) { codesignCommonName = identity.SigningKey != null?GetCertificateCommonName(identity.SigningKey) : null; provisioningProfileName = identity.Profile.Name; DetectedAppId = identity.AppId; DetectedCodeSigningPath = identity.SigningKey != null?Path.Combine(CertificatesPath, $"{identity.SigningKey.SerialNumber}.p12") : string.Empty; DetectedProvisioningProfileId = identity.Profile.Uuid; DetectedProvisioningProfilePath = Path.Combine(ProfilesPath, $"{DetectedProvisioningProfileId}.mobileprovision"); ReportDetectedCodesignInfo(); } else { if (identity.SigningKey != null) { Log.LogError("Bundle identifier '{0}' does not match any installed provisioning profile for selected signing identity '{0}'. Please enable Automatic Provisioning from the iOS Bundle Signing page.", identity.BundleId, identity.SigningKey); } else { Log.LogError("Bundle identifier '{0}' does not match any installed provisioning profile. Please enable Automatic Provisioning from the iOS Bundle Signing page.", identity.BundleId); } } return(!Log.HasLoggedErrors); }
CodeSignIdentity GetBestMatch(List <CodeSignIdentity> pairs, CodeSignIdentity identity) { var matches = new List <CodeSignIdentity> (); int bestMatchLength = 0; int matchLength; // find matching provisioning profiles with compatible appid, keeping only those with the longest matching (wildcard) ids Log.LogMessage(MessageImportance.Low, "Finding matching provisioning profiles with compatible AppID, keeping only those with the longest matching (wildcard) IDs."); foreach (var pair in pairs) { var appid = ConstructValidAppId(pair.Profile, identity.BundleId, out matchLength); if (appid != null) { if (matchLength >= bestMatchLength) { if (matchLength > bestMatchLength) { bestMatchLength = matchLength; foreach (var previousMatch in matches) { Log.LogMessage(MessageImportance.Low, "AppID: {0} was ruled out because we found a better match: {1}.", previousMatch.AppId, appid); } matches.Clear(); } var match = identity.Clone(); match.SigningKey = pair.SigningKey; match.Profile = pair.Profile; match.AppId = appid; matches.Add(match); } else { string currentMatches = ""; foreach (var match in matches) { currentMatches += $"{match}; "; } Log.LogMessage(MessageImportance.Low, "AppID: {0} was ruled out because we already found better matches: {1}.", appid, currentMatches); } } } if (matches.Count == 0) { Log.LogWarning(null, null, null, AppManifest, 0, 0, 0, 0, "No installed provisioning profiles match the bundle identifier."); return(identity); } if (matches.Count > 1) { var spaces = new string (' ', 3); Log.LogMessage(MessageImportance.Normal, "Multiple provisioning profiles match the bundle identifier; using the first match."); matches.Sort(new SigningIdentityComparer()); for (int i = 0; i < matches.Count; i++) { Log.LogMessage(MessageImportance.Normal, "{0,3}. Provisioning Profile: \"{1}\" ({2})", i + 1, matches [i].Profile.Name, matches [i].Profile.Uuid); if (matches [i].SigningKey != null) { Log.LogMessage(MessageImportance.Normal, "{0} Signing Identity: \"{1}\"", spaces, GetCertificateCommonName(matches [i].SigningKey)); } } } return(matches [0]); }
IList <MobileProvision> GetProvisioningProfiles(MobileProvisionPlatform platform, MobileProvisionDistributionType type, CodeSignIdentity identity, IList <X509Certificate2> certs) { var failures = new List <string> (); IList <MobileProvision> profiles; if (identity.BundleId != null) { if (certs.Count > 0) { profiles = MobileProvisionIndex.GetMobileProvisions(platform, identity.BundleId, type, certs, unique: true, failures: failures); } else { profiles = MobileProvisionIndex.GetMobileProvisions(platform, identity.BundleId, type, unique: true, failures: failures); } } else if (certs.Count > 0) { profiles = MobileProvisionIndex.GetMobileProvisions(platform, type, certs, unique: true, failures: failures); } else { profiles = MobileProvisionIndex.GetMobileProvisions(platform, type, unique: true, failures: failures); } if (profiles.Count == 0) { foreach (var f in failures) { Log.LogMessage(MessageImportance.Low, "{0}", f); } Log.LogError($"Could not find any available provisioning profiles for {PlatformName}. Please enable Automatic Provisioning from the iOS Bundle Signing page."); return(null); } Log.LogMessage(MessageImportance.Low, "Available profiles:"); foreach (var p in profiles) { Log.LogMessage(MessageImportance.Low, " {0}", p.Name); } return(profiles); }
public override bool Execute() { var type = MobileProvisionDistributionType.Any; var identity = new CodeSignIdentity(); MobileProvisionPlatform platform; IList <MobileProvision> profiles; IList <X509Certificate2> certs; List <CodeSignIdentity> pairs; switch (SdkPlatform) { case "AppleTVSimulator": case "AppleTVOS": platform = MobileProvisionPlatform.tvOS; break; case "iPhoneSimulator": case "WatchSimulator": case "iPhoneOS": case "WatchOS": platform = MobileProvisionPlatform.iOS; break; case "MacOSX": platform = MobileProvisionPlatform.MacOS; break; case "MacCatalyst": platform = MobileProvisionPlatform.MacOS; break; default: Log.LogError(MSBStrings.E0048, SdkPlatform); return(false); } if (ProvisioningProfile == AutomaticAppStoreProvision) { type = MobileProvisionDistributionType.AppStore; } else if (ProvisioningProfile == AutomaticInHouseProvision) { type = MobileProvisionDistributionType.InHouse; } else if (ProvisioningProfile == AutomaticAdHocProvision) { type = MobileProvisionDistributionType.AdHoc; } DetectedCodesignAllocate = Path.Combine(DeveloperRoot, "Toolchains", "XcodeDefault.xctoolchain", "usr", "bin", "codesign_allocate"); DetectedDistributionType = type.ToString(); identity.BundleId = BundleIdentifier; DetectedAppId = BundleIdentifier; // default value that can be changed below if (Platform == ApplePlatform.MacOSX) { if (!RequireCodeSigning || !string.IsNullOrEmpty(DetectedCodeSigningKey)) { ReportDetectedCodesignInfo(); return(!Log.HasLoggedErrors); } } else if (Platform == ApplePlatform.MacCatalyst) { var doesNotNeedCodeSigningCertificate = !RequireCodeSigning || !string.IsNullOrEmpty(DetectedCodeSigningKey); if (RequireProvisioningProfile) { doesNotNeedCodeSigningCertificate = false; } if (doesNotNeedCodeSigningCertificate) { DetectedCodeSigningKey = "-"; ReportDetectedCodesignInfo(); return(!Log.HasLoggedErrors); } } else { // Framework is either iOS, tvOS or watchOS if (SdkIsSimulator) { if (AppleSdkSettings.XcodeVersion.Major >= 8 && RequireProvisioningProfile) { // Note: Starting with Xcode 8.0, we need to codesign iOS Simulator builds that enable Entitlements // in order for them to run. The "-" key is a special value allowed by the codesign utility that // allows us to get away with not having an actual codesign key. DetectedCodeSigningKey = "-"; if (!IsAutoCodeSignProfile(ProvisioningProfile)) { identity.Profile = MobileProvisionIndex.GetMobileProvision(platform, ProvisioningProfile); if (identity.Profile == null) { Log.LogError(MSBStrings.E0140, PlatformName, ProvisioningProfile); return(false); } identity.AppId = ConstructValidAppId(identity.Profile, identity.BundleId); if (identity.AppId == null) { Log.LogError(MSBStrings.E0141, identity.BundleId, ProvisioningProfile); return(false); } provisioningProfileName = identity.Profile.Name; DetectedProvisioningProfile = identity.Profile.Uuid; DetectedDistributionType = identity.Profile.DistributionType.ToString(); } else { certs = new X509Certificate2[0]; if ((profiles = GetProvisioningProfiles(platform, type, identity, certs)) == null) { return(false); } if ((pairs = GetCodeSignIdentityPairs(profiles, certs)) == null) { return(false); } var match = GetBestMatch(pairs, identity); identity.Profile = match.Profile; identity.AppId = match.AppId; if (identity.Profile != null) { DetectedDistributionType = identity.Profile.DistributionType.ToString(); DetectedProvisioningProfile = identity.Profile.Uuid; provisioningProfileName = identity.Profile.Name; } DetectedAppId = identity.AppId; } } else { // Note: Do not codesign. Codesigning seems to break the iOS Simulator in older versions of Xcode. DetectedCodeSigningKey = null; } ReportDetectedCodesignInfo(); return(!Log.HasLoggedErrors); } } // Note: if we make it this far, we absolutely need a codesigning certificate if (!TryGetSigningCertificates(out certs, false)) { return(false); } Log.LogMessage(MessageImportance.Low, "Available certificates:"); foreach (var cert in certs) { Log.LogMessage(MessageImportance.Low, " {0}", SecKeychain.GetCertificateCommonName(cert)); } if (!RequireProvisioningProfile) { if (certs.Count > 1) { if (!string.IsNullOrEmpty(SigningKey)) { Log.LogMessage(MessageImportance.Normal, MSBStrings.M0142, SigningKey); } else { Log.LogMessage(MessageImportance.Normal, MSBStrings.M0143); } for (int i = 0; i < certs.Count; i++) { Log.LogMessage(MessageImportance.Normal, "{0,3}. Signing Identity: {1} ({2})", i + 1, SecKeychain.GetCertificateCommonName(certs[i]), certs[i].Thumbprint); } } codesignCommonName = SecKeychain.GetCertificateCommonName(certs[0]); DetectedCodeSigningKey = certs[0].Thumbprint; ReportDetectedCodesignInfo(); return(!Log.HasLoggedErrors); } if (!IsAutoCodeSignProfile(ProvisioningProfile)) { identity.Profile = MobileProvisionIndex.GetMobileProvision(platform, ProvisioningProfile); if (identity.Profile == null) { Log.LogError(MSBStrings.E0144, PlatformName, ProvisioningProfile); return(false); } var profile = identity.Profile; // capture ref for lambda if (certs.Count > 0) { identity.SigningKey = certs.FirstOrDefault(c => profile.DeveloperCertificates.Any(p => p.Thumbprint == c.Thumbprint)); if (identity.SigningKey == null) { Log.LogError(MSBStrings.E0145, PlatformName, ProvisioningProfile); return(false); } } identity.AppId = ConstructValidAppId(identity.Profile, identity.BundleId); if (identity.AppId == null) { Log.LogError(MSBStrings.E0141, identity.BundleId, ProvisioningProfile); return(false); } if (identity.SigningKey != null) { codesignCommonName = SecKeychain.GetCertificateCommonName(identity.SigningKey); DetectedCodeSigningKey = identity.SigningKey.Thumbprint; } provisioningProfileName = identity.Profile.Name; DetectedProvisioningProfile = identity.Profile.Uuid; DetectedDistributionType = identity.Profile.DistributionType.ToString(); DetectedAppId = identity.AppId; ReportDetectedCodesignInfo(); return(!Log.HasLoggedErrors); } if ((profiles = GetProvisioningProfiles(platform, type, identity, certs)) == null) { return(false); } if ((pairs = GetCodeSignIdentityPairs(profiles, certs)) == null) { return(false); } identity = GetBestMatch(pairs, identity); if (identity.Profile != null && identity.AppId != null) { codesignCommonName = identity.SigningKey != null?SecKeychain.GetCertificateCommonName(identity.SigningKey) : null; provisioningProfileName = identity.Profile.Name; DetectedCodeSigningKey = identity.SigningKey?.Thumbprint; DetectedProvisioningProfile = identity.Profile.Uuid; DetectedAppId = identity.AppId; ReportDetectedCodesignInfo(); } else { if (identity.SigningKey != null) { Log.LogError(MSBStrings.E0146, identity.BundleId, identity.SigningKey); } else { Log.LogError(MSBStrings.E0148, identity.BundleId); } } return(!Log.HasLoggedErrors); }
IList <MobileProvision> GetProvisioningProfiles(MobileProvisionPlatform platform, MobileProvisionDistributionType type, CodeSignIdentity identity, IList <X509Certificate2> certs) { var failures = new List <string> (); IList <MobileProvision> profiles; if (identity.BundleId != null) { if (certs.Count > 0) { profiles = MobileProvisionIndex.GetMobileProvisions(platform, identity.BundleId, type, certs, unique: true, failures: failures); } else { profiles = MobileProvisionIndex.GetMobileProvisions(platform, identity.BundleId, type, unique: true, failures: failures); } } else if (certs.Count > 0) { profiles = MobileProvisionIndex.GetMobileProvisions(platform, type, certs, unique: true, failures: failures); } else { profiles = MobileProvisionIndex.GetMobileProvisions(platform, type, unique: true, failures: failures); } if (profiles.Count == 0) { foreach (var f in failures) { Log.LogMessage(MessageImportance.Low, "{0}", f); } Log.LogError(MSBStrings.E0131, AppBundleName, PlatformName); return(null); } Log.LogMessage(MessageImportance.Low, "Available profiles:"); foreach (var p in profiles) { Log.LogMessage(MessageImportance.Low, " {0}", p.Name); } return(profiles); }
public override bool Execute() { var type = MobileProvisionDistributionType.Any; var identity = new CodeSignIdentity(); MobileProvisionPlatform platform; IList <MobileProvision> profiles; IList <X509Certificate2> certs; PDictionary plist; switch (SdkPlatform) { case "AppleTVSimulator": case "AppleTVOS": platform = MobileProvisionPlatform.tvOS; break; case "iPhoneSimulator": case "WatchSimulator": case "iPhoneOS": case "WatchOS": platform = MobileProvisionPlatform.iOS; break; case "MacOSX": platform = MobileProvisionPlatform.MacOS; break; default: Log.LogError("Unknown SDK platform: {0}", SdkPlatform); return(false); } if (ProvisioningProfile == AutomaticAppStoreProvision) { type = MobileProvisionDistributionType.AppStore; } else if (ProvisioningProfile == AutomaticInHouseProvision) { type = MobileProvisionDistributionType.InHouse; } else if (ProvisioningProfile == AutomaticAdHocProvision) { type = MobileProvisionDistributionType.AdHoc; } try { plist = PDictionary.FromFile(AppManifest); } catch (Exception ex) { Log.LogError(null, null, null, AppManifest, 0, 0, 0, 0, "Error loading '{0}': {1}", AppManifest, ex.Message); return(false); } DetectedCodesignAllocate = Path.Combine(DeveloperRoot, "Toolchains", "XcodeDefault.xctoolchain", "usr", "bin", "codesign_allocate"); DetectedBundleVersion = plist.GetCFBundleVersion(); DetectedDistributionType = type.ToString(); identity.BundleId = plist.GetCFBundleIdentifier(); if (string.IsNullOrEmpty(identity.BundleId)) { Log.LogError(null, null, null, AppManifest, 0, 0, 0, 0, "{0} does not define CFBundleIdentifier", AppManifest); return(false); } if (Framework == PlatformFramework.MacOS && !RequireCodeSigning) { DetectedBundleId = identity.BundleId; DetectedAppId = DetectedBundleId; ReportDetectedCodesignInfo(); return(!Log.HasLoggedErrors); } if (!RequireProvisioningProfile && string.IsNullOrEmpty(ProvisioningProfile)) { if (SdkIsSimulator && AppleSdkSettings.XcodeVersion.Major >= 8) { // Note: Starting with Xcode 8.0, we need to codesign iOS Simulator builds in order for them to run. // The "-" key is a special value allowed by the codesign utility that allows us to get away with // not having an actual codesign key. As far as we know, this only works with Xcode >= 8. DetectedCodeSigningKey = "-"; } else { // Try and get a valid codesigning certificate... if (!TryGetSigningCertificates(out certs, SdkIsSimulator)) { return(false); } if (certs.Count > 0) { if (certs.Count > 1) { if (!string.IsNullOrEmpty(SigningKey)) { Log.LogMessage(MessageImportance.Normal, "Multiple signing identities match '{0}'; using the first match.", SigningKey); } else { Log.LogMessage(MessageImportance.Normal, "Multiple signing identities found; using the first identity."); } for (int i = 0; i < certs.Count; i++) { Log.LogMessage(MessageImportance.Normal, "{0,3}. Signing Identity: {1} ({2})", i + 1, SecKeychain.GetCertificateCommonName(certs[i]), certs[i].Thumbprint); } } codesignCommonName = SecKeychain.GetCertificateCommonName(certs[0]); DetectedCodeSigningKey = certs[0].Thumbprint; } else { // Note: We don't have to codesign for iOS Simulator builds meant to run on Xcode iOS Simulators // older than 8.0, so it's non-fatal if we don't find any... } } DetectedBundleId = identity.BundleId; DetectedAppId = DetectedBundleId; ReportDetectedCodesignInfo(); return(!Log.HasLoggedErrors); } // Note: if we make it this far, we absolutely need a codesigning certificate if (!TryGetSigningCertificates(out certs, false)) { return(false); } if (certs.Count > 0) { Log.LogMessage(MessageImportance.Low, "Available certificates:"); foreach (var cert in certs) { Log.LogMessage(MessageImportance.Low, " {0}", Xamarin.MacDev.Keychain.GetCertificateCommonName(cert)); } } if (!IsAutoCodeSignProfile(ProvisioningProfile)) { identity.Profile = MobileProvisionIndex.GetMobileProvision(platform, ProvisioningProfile); if (identity.Profile == null) { Log.LogError("The specified " + PlatformName + " provisioning profile '{0}' could not be found", ProvisioningProfile); return(false); } var profile = identity.Profile; // capture ref for lambda if (certs.Count > 0) { identity.SigningKey = certs.FirstOrDefault(c => profile.DeveloperCertificates.Any(p => p.Thumbprint == c.Thumbprint)); if (identity.SigningKey == null) { Log.LogError("No " + PlatformName + " signing identities match the specified provisioning profile '{0}'.", ProvisioningProfile); return(false); } } identity.AppId = ConstructValidAppId(identity.Profile, identity.BundleId); if (identity.AppId == null) { Log.LogError(null, null, null, AppManifest, 0, 0, 0, 0, "Project bundle identifier '{0}' does not match specified provisioning profile '{1}'", identity.BundleId, ProvisioningProfile); return(false); } if (identity.SigningKey != null) { codesignCommonName = SecKeychain.GetCertificateCommonName(identity.SigningKey); DetectedCodeSigningKey = identity.SigningKey.Thumbprint; } provisioningProfileName = identity.Profile.Name; DetectedProvisioningProfile = identity.Profile.Uuid; DetectedDistributionType = identity.Profile.DistributionType.ToString(); DetectedBundleId = identity.BundleId; DetectedAppId = identity.AppId; ReportDetectedCodesignInfo(); return(!Log.HasLoggedErrors); } List <string> failures = new List <string> (); if (identity.BundleId != null) { if (certs.Count > 0) { profiles = MobileProvisionIndex.GetMobileProvisions(platform, identity.BundleId, type, certs, unique: true, failures: failures); } else { profiles = MobileProvisionIndex.GetMobileProvisions(platform, identity.BundleId, type, unique: true, failures: failures); } } else if (certs.Count > 0) { profiles = MobileProvisionIndex.GetMobileProvisions(platform, type, certs, unique: true, failures: failures); } else { profiles = MobileProvisionIndex.GetMobileProvisions(platform, type, unique: true, failures: failures); } if (profiles.Count == 0) { foreach (var f in failures) { Log.LogMessage(MessageImportance.Low, "{0}", f); } Log.LogError($"Could not find any available provisioning profiles for {PlatformName}."); return(false); } else { Log.LogMessage(MessageImportance.Low, "Available profiles:"); foreach (var p in profiles) { Log.LogMessage(MessageImportance.Low, " {0}", p.Name); } } List <CodeSignIdentity> pairs; if (certs.Count > 0) { pairs = (from p in profiles from c in certs where p.DeveloperCertificates.Any(d => d.Thumbprint == c.Thumbprint) select new CodeSignIdentity { SigningKey = c, Profile = p }).ToList(); if (pairs.Count == 0) { Log.LogError("No installed provisioning profiles match the installed " + PlatformName + " signing identities."); return(false); } } else { pairs = (from p in profiles select new CodeSignIdentity { Profile = p }).ToList(); } var matches = new List <CodeSignIdentity> (); int bestMatchLength = 0; int matchLength; // find matching provisioning profiles with compatible appid, keeping only those with the longest matching (wildcard) ids foreach (var pair in pairs) { var appid = ConstructValidAppId(pair.Profile, identity.BundleId, out matchLength); if (appid != null && matchLength >= bestMatchLength) { if (matchLength > bestMatchLength) { bestMatchLength = matchLength; matches.Clear(); } var match = identity.Clone(); match.SigningKey = pair.SigningKey; match.Profile = pair.Profile; match.AppId = appid; matches.Add(match); } } if (matches.Count == 0) { Log.LogWarning(null, null, null, AppManifest, 0, 0, 0, 0, "No installed provisioning profiles match the bundle identifier."); } else { if (matches.Count > 1) { var spaces = new string (' ', 3); Log.LogMessage(MessageImportance.Normal, "Multiple provisioning profiles match the bundle identifier; using the first match."); matches.Sort(new SigningIdentityComparer()); for (int i = 0; i < matches.Count; i++) { Log.LogMessage(MessageImportance.Normal, "{0,3}. Provisioning Profile: \"{1}\" ({2})", i + 1, matches[i].Profile.Name, matches[i].Profile.Uuid); if (matches[i].SigningKey != null) { Log.LogMessage(MessageImportance.Normal, "{0} Signing Identity: \"{1}\"", spaces, SecKeychain.GetCertificateCommonName(matches[i].SigningKey)); } } } identity = matches[0]; } if (identity.Profile != null && identity.AppId != null) { codesignCommonName = identity.SigningKey != null?SecKeychain.GetCertificateCommonName(identity.SigningKey) : null; provisioningProfileName = identity.Profile.Name; DetectedCodeSigningKey = identity.SigningKey?.Thumbprint; DetectedProvisioningProfile = identity.Profile.Uuid; DetectedBundleId = identity.BundleId; DetectedAppId = identity.AppId; ReportDetectedCodesignInfo(); } else { if (identity.SigningKey != null) { Log.LogError("Bundle identifier '{0}' does not match any installed provisioning profile for selected signing identity '{0}'.", identity.BundleId, identity.SigningKey); } else { Log.LogError("Bundle identifier '{0}' does not match any installed provisioning profile.", identity.BundleId); } } return(!Log.HasLoggedErrors); }
public override bool Execute() { var type = MobileProvisionDistributionType.Any; var identity = new CodeSignIdentity(); MobileProvisionPlatform platform; IList <MobileProvision> profiles; IList <X509Certificate2> certs; List <CodeSignIdentity> pairs; PDictionary plist; switch (SdkPlatform) { case "AppleTVSimulator": case "AppleTVOS": platform = MobileProvisionPlatform.tvOS; break; case "iPhoneSimulator": case "WatchSimulator": case "iPhoneOS": case "WatchOS": platform = MobileProvisionPlatform.iOS; break; case "MacOSX": platform = MobileProvisionPlatform.MacOS; break; default: Log.LogError("Unknown SDK platform: {0}", SdkPlatform); return(false); } if (ProvisioningProfile == AutomaticAppStoreProvision) { type = MobileProvisionDistributionType.AppStore; } else if (ProvisioningProfile == AutomaticInHouseProvision) { type = MobileProvisionDistributionType.InHouse; } else if (ProvisioningProfile == AutomaticAdHocProvision) { type = MobileProvisionDistributionType.AdHoc; } try { plist = PDictionary.FromFile(AppManifest); } catch (Exception ex) { Log.LogError(null, null, null, AppManifest, 0, 0, 0, 0, "Error loading '{0}': {1}", AppManifest, ex.Message); return(false); } DetectedCodesignAllocate = Path.Combine(DeveloperRoot, "Toolchains", "XcodeDefault.xctoolchain", "usr", "bin", "codesign_allocate"); DetectedBundleVersion = plist.GetCFBundleVersion(); DetectedDistributionType = type.ToString(); identity.BundleId = plist.GetCFBundleIdentifier(); if (string.IsNullOrEmpty(identity.BundleId)) { Log.LogError(null, null, null, AppManifest, 0, 0, 0, 0, "{0} does not define CFBundleIdentifier", AppManifest); return(false); } if (Framework == PlatformFramework.MacOS) { if (!RequireCodeSigning) { DetectedBundleId = identity.BundleId; DetectedAppId = DetectedBundleId; ReportDetectedCodesignInfo(); return(!Log.HasLoggedErrors); } } else { // Framework is either iOS, tvOS or watchOS if (SdkIsSimulator) { if (AppleSdkSettings.XcodeVersion.Major >= 8 && RequireProvisioningProfile) { // Note: Starting with Xcode 8.0, we need to codesign iOS Simulator builds that enable Entitlements // in order for them to run. The "-" key is a special value allowed by the codesign utility that // allows us to get away with not having an actual codesign key. DetectedCodeSigningKey = "-"; if (!IsAutoCodeSignProfile(ProvisioningProfile)) { identity.Profile = MobileProvisionIndex.GetMobileProvision(platform, ProvisioningProfile); if (identity.Profile == null) { Log.LogError("The specified " + PlatformName + " provisioning profile '{0}' could not be found", ProvisioningProfile); return(false); } identity.AppId = ConstructValidAppId(identity.Profile, identity.BundleId); if (identity.AppId == null) { Log.LogError(null, null, null, AppManifest, 0, 0, 0, 0, "Project bundle identifier '{0}' does not match specified provisioning profile '{1}'", identity.BundleId, ProvisioningProfile); return(false); } provisioningProfileName = identity.Profile.Name; DetectedProvisioningProfile = identity.Profile.Uuid; DetectedDistributionType = identity.Profile.DistributionType.ToString(); DetectedBundleId = identity.BundleId; DetectedAppId = DetectedBundleId; } else { certs = new X509Certificate2[0]; if ((profiles = GetProvisioningProfiles(platform, type, identity, certs)) == null) { return(false); } if ((pairs = GetCodeSignIdentityPairs(profiles, certs)) == null) { return(false); } var match = GetBestMatch(pairs, identity); identity.Profile = match.Profile; identity.AppId = match.AppId; if (identity.Profile != null) { DetectedDistributionType = identity.Profile.DistributionType.ToString(); DetectedProvisioningProfile = identity.Profile.Uuid; provisioningProfileName = identity.Profile.Name; } DetectedBundleId = identity.BundleId; DetectedAppId = identity.AppId; } } else { // Note: Do not codesign. Codesigning seems to break the iOS Simulator in older versions of Xcode. DetectedCodeSigningKey = null; DetectedBundleId = identity.BundleId; DetectedAppId = DetectedBundleId; } ReportDetectedCodesignInfo(); return(!Log.HasLoggedErrors); } } // Note: if we make it this far, we absolutely need a codesigning certificate if (!TryGetSigningCertificates(out certs, false)) { return(false); } Log.LogMessage(MessageImportance.Low, "Available certificates:"); foreach (var cert in certs) { Log.LogMessage(MessageImportance.Low, " {0}", SecKeychain.GetCertificateCommonName(cert)); } if (!RequireProvisioningProfile) { if (certs.Count > 1) { if (!string.IsNullOrEmpty(SigningKey)) { Log.LogMessage(MessageImportance.Normal, "Multiple signing identities match '{0}'; using the first match.", SigningKey); } else { Log.LogMessage(MessageImportance.Normal, "Multiple signing identities found; using the first identity."); } for (int i = 0; i < certs.Count; i++) { Log.LogMessage(MessageImportance.Normal, "{0,3}. Signing Identity: {1} ({2})", i + 1, SecKeychain.GetCertificateCommonName(certs[i]), certs[i].Thumbprint); } } codesignCommonName = SecKeychain.GetCertificateCommonName(certs[0]); DetectedCodeSigningKey = certs[0].Thumbprint; DetectedBundleId = identity.BundleId; DetectedAppId = DetectedBundleId; ReportDetectedCodesignInfo(); return(!Log.HasLoggedErrors); } if (!IsAutoCodeSignProfile(ProvisioningProfile)) { identity.Profile = MobileProvisionIndex.GetMobileProvision(platform, ProvisioningProfile); if (identity.Profile == null) { Log.LogError("The specified " + PlatformName + " provisioning profile '{0}' could not be found", ProvisioningProfile); return(false); } var profile = identity.Profile; // capture ref for lambda if (certs.Count > 0) { identity.SigningKey = certs.FirstOrDefault(c => profile.DeveloperCertificates.Any(p => p.Thumbprint == c.Thumbprint)); if (identity.SigningKey == null) { Log.LogError("No " + PlatformName + " signing identities match the specified provisioning profile '{0}'.", ProvisioningProfile); return(false); } } identity.AppId = ConstructValidAppId(identity.Profile, identity.BundleId); if (identity.AppId == null) { Log.LogError(null, null, null, AppManifest, 0, 0, 0, 0, "Project bundle identifier '{0}' does not match specified provisioning profile '{1}'", identity.BundleId, ProvisioningProfile); return(false); } if (identity.SigningKey != null) { codesignCommonName = SecKeychain.GetCertificateCommonName(identity.SigningKey); DetectedCodeSigningKey = identity.SigningKey.Thumbprint; } provisioningProfileName = identity.Profile.Name; DetectedProvisioningProfile = identity.Profile.Uuid; DetectedDistributionType = identity.Profile.DistributionType.ToString(); DetectedBundleId = identity.BundleId; DetectedAppId = identity.AppId; ReportDetectedCodesignInfo(); return(!Log.HasLoggedErrors); } if ((profiles = GetProvisioningProfiles(platform, type, identity, certs)) == null) { return(false); } if ((pairs = GetCodeSignIdentityPairs(profiles, certs)) == null) { return(false); } identity = GetBestMatch(pairs, identity); if (identity.Profile != null && identity.AppId != null) { codesignCommonName = identity.SigningKey != null?SecKeychain.GetCertificateCommonName(identity.SigningKey) : null; provisioningProfileName = identity.Profile.Name; DetectedCodeSigningKey = identity.SigningKey?.Thumbprint; DetectedProvisioningProfile = identity.Profile.Uuid; DetectedBundleId = identity.BundleId; DetectedAppId = identity.AppId; ReportDetectedCodesignInfo(); } else { if (identity.SigningKey != null) { Log.LogError("Bundle identifier '{0}' does not match any installed provisioning profile for selected signing identity '{0}'.", identity.BundleId, identity.SigningKey); } else { Log.LogError("Bundle identifier '{0}' does not match any installed provisioning profile.", identity.BundleId); } } return(!Log.HasLoggedErrors); }
public override bool Execute() { var type = MobileProvisionDistributionType.Any; var identity = new CodeSignIdentity(); MobileProvisionPlatform platform; IList <MobileProvision> profiles; IList <X509Certificate2> certs; PDictionary plist; Log.LogTaskName("DetectSigningIdentity"); Log.LogTaskProperty("AppBundleName", AppBundleName); Log.LogTaskProperty("AppManifest", AppManifest); Log.LogTaskProperty("Keychain", Keychain); Log.LogTaskProperty("ProvisioningProfile", ProvisioningProfile); Log.LogTaskProperty("RequireCodesigning", RequireCodeSigning); Log.LogTaskProperty("RequireProvisioningProfile", RequireProvisioningProfile); Log.LogTaskProperty("SdkPlatform", SdkPlatform); Log.LogTaskProperty("SdkIsSimulator", SdkIsSimulator); Log.LogTaskProperty("SigningKey", SigningKey); switch (SdkPlatform) { case "AppleTVSimulator": case "AppleTVOS": platform = MobileProvisionPlatform.tvOS; break; case "iPhoneSimulator": case "WatchSimulator": case "iPhoneOS": case "WatchOS": platform = MobileProvisionPlatform.iOS; break; case "MacOSX": platform = MobileProvisionPlatform.MacOS; break; default: Log.LogError("Unknown SDK platform: {0}", SdkPlatform); return(false); } if (ProvisioningProfile == AutomaticAppStoreProvision) { type = MobileProvisionDistributionType.AppStore; } else if (ProvisioningProfile == AutomaticInHouseProvision) { type = MobileProvisionDistributionType.InHouse; } else if (ProvisioningProfile == AutomaticAdHocProvision) { type = MobileProvisionDistributionType.AdHoc; } try { plist = PDictionary.FromFile(AppManifest); } catch (Exception ex) { Log.LogError(null, null, null, AppManifest, 0, 0, 0, 0, "Error loading '{0}': {1}", AppManifest, ex.Message); return(false); } DetectedCodesignAllocate = Path.Combine(DeveloperRoot, "Toolchains", "XcodeDefault.xctoolchain", "usr", "bin", "codesign_allocate"); DetectedBundleVersion = plist.GetCFBundleVersion(); DetectedDistributionType = type.ToString(); identity.BundleId = plist.GetCFBundleIdentifier(); if (string.IsNullOrEmpty(identity.BundleId)) { identity.BundleId = null; } if (Framework == PlatformFramework.MacOS && !RequireCodeSigning) { DetectedBundleId = identity.BundleId ?? GetDefaultBundleId(AppBundleName, null); DetectedAppId = DetectedBundleId; ReportDetectedCodesignInfo(); return(!Log.HasLoggedErrors); } try { var keychain = !string.IsNullOrEmpty(Keychain) ? SecKeychain.Open(Keychain) : SecKeychain.Default; if (string.IsNullOrEmpty(SigningKey) || MatchesAny(SigningKey, DevelopmentPrefixes)) { // Note: we treat an empty signing key as "developer automatic". if (!TryGetSigningCertificates(keychain, out certs, DevelopmentPrefixes)) { return(false); } } else if (MatchesAny(SigningKey, AppStoreDistributionPrefixes)) { if (!TryGetSigningCertificates(keychain, out certs, AppStoreDistributionPrefixes)) { return(false); } } else if (MatchesAny(SigningKey, DirectDistributionPrefixes)) { if (!TryGetSigningCertificates(keychain, out certs, DirectDistributionPrefixes)) { return(false); } } else { // The user has specified an exact name to match... if (!TryGetSigningCertificates(keychain, out certs, SigningKey)) { return(false); } } } catch (Exception ex) { Log.LogError("{0}", ex.Message); return(false); } if (!RequireProvisioningProfile && string.IsNullOrEmpty(ProvisioningProfile)) { if (certs.Count > 1) { if (!string.IsNullOrEmpty(SigningKey)) { Log.LogMessage(MessageImportance.Normal, "Multiple signing identities match '{0}'; using the first match.", SigningKey); } else { Log.LogMessage(MessageImportance.Normal, "Multiple signing identities found; using the first identity."); } for (int i = 0; i < certs.Count; i++) { Log.LogMessage(MessageImportance.Normal, "{0,3}. Signing Identity: {1} ({2})", i + 1, SecKeychain.GetCertificateCommonName(certs[i]), certs[i].Thumbprint); } } codesignCommonName = SecKeychain.GetCertificateCommonName(certs[0]); DetectedCodeSigningKey = certs[0].Thumbprint; DetectedBundleId = identity.BundleId ?? GetDefaultBundleId(AppBundleName, null); DetectedAppId = DetectedBundleId; ReportDetectedCodesignInfo(); return(!Log.HasLoggedErrors); } if (!IsAutoCodeSignProfile(ProvisioningProfile)) { identity.Profile = MobileProvisionIndex.GetMobileProvision(platform, ProvisioningProfile); if (identity.Profile == null) { Log.LogError("The specified " + PlatformName + " provisioning profile '{0}' could not be found", ProvisioningProfile); return(false); } var profile = identity.Profile; // capture ref for lambda if (certs.Count > 0) { identity.SigningKey = certs.FirstOrDefault(c => profile.DeveloperCertificates.Any(p => p.Thumbprint == c.Thumbprint)); if (identity.SigningKey == null) { Log.LogError("No " + PlatformName + " signing identities match the specified provisioning profile '{0}'.", ProvisioningProfile); return(false); } } if (identity.BundleId == null) { identity.BundleId = GetDefaultBundleId(AppBundleName, GetProfileBundleId(identity.Profile)); Log.LogWarning(null, null, null, AppManifest, 0, 0, 0, 0, "Project does not have bundle identifier specified. Using '{0}' to match provisioning profile.", identity.BundleId); } identity.AppId = ConstructValidAppId(identity.Profile, identity.BundleId); if (identity.AppId == null) { Log.LogError(null, null, null, AppManifest, 0, 0, 0, 0, "Project bundle identifier '{0}' does not match specified provisioning profile '{1}'", identity.BundleId, ProvisioningProfile); return(false); } if (identity.SigningKey != null) { codesignCommonName = SecKeychain.GetCertificateCommonName(identity.SigningKey); DetectedCodeSigningKey = identity.SigningKey.Thumbprint; } provisioningProfileName = identity.Profile.Name; DetectedProvisioningProfile = identity.Profile.Uuid; DetectedDistributionType = identity.Profile.DistributionType.ToString(); DetectedBundleId = identity.BundleId; DetectedAppId = identity.AppId; ReportDetectedCodesignInfo(); return(!Log.HasLoggedErrors); } if (identity.BundleId != null) { if (certs.Count > 0) { profiles = MobileProvisionIndex.GetMobileProvisions(platform, identity.BundleId, type, certs); } else { profiles = MobileProvisionIndex.GetMobileProvisions(platform, identity.BundleId, type); } } else if (certs.Count > 0) { profiles = MobileProvisionIndex.GetMobileProvisions(platform, type, certs); } else { profiles = MobileProvisionIndex.GetMobileProvisions(platform, type); } List <CodeSignIdentity> pairs; if (certs.Count > 0) { pairs = (from p in profiles from c in certs where p.DeveloperCertificates.Any(d => d.Thumbprint == c.Thumbprint) select new CodeSignIdentity { SigningKey = c, Profile = p }).ToList(); if (pairs.Count == 0) { Log.LogError("No installed provisioning profiles match the installed " + PlatformName + " signing identities."); return(false); } } else { pairs = (from p in profiles select new CodeSignIdentity { Profile = p }).ToList(); } if (identity.BundleId != null) { var matches = new List <CodeSignIdentity> (); int bestMatchLength = 0; int matchLength; // find matching provisioning profiles with compatible appid, keeping only those with the longest matching (wildcard) ids foreach (var pair in pairs) { var appid = ConstructValidAppId(pair.Profile, identity.BundleId, out matchLength); if (appid != null && matchLength >= bestMatchLength) { if (matchLength > bestMatchLength) { bestMatchLength = matchLength; matches.Clear(); } var match = identity.Clone(); match.SigningKey = pair.SigningKey; match.Profile = pair.Profile; match.AppId = appid; matches.Add(match); } } if (matches.Count == 0) { Log.LogWarning(null, null, null, AppManifest, 0, 0, 0, 0, "No installed provisioning profiles match the bundle identifier."); } else { if (matches.Count > 1) { var spaces = new string (' ', 3); Log.LogMessage(MessageImportance.Normal, "Multiple provisioning profiles match the bundle identifier; using the first match."); matches.Sort(new SigningIdentityComparer()); for (int i = 0; i < matches.Count; i++) { Log.LogMessage(MessageImportance.Normal, "{0,3}. Provisioning Profile: \"{1}\" ({2})", i + 1, matches[i].Profile.Name, matches[i].Profile.Uuid); if (matches[i].SigningKey != null) { Log.LogMessage(MessageImportance.Normal, "{0} Signing Identity: \"{1}\"", spaces, SecKeychain.GetCertificateCommonName(matches[i].SigningKey)); } } } identity = matches[0]; } } else { // pick a provisioning profile to provide appid and better default bundle identifier, preferring wildcard bundle identifiers foreach (var pair in pairs) { var suggestion = GetProfileBundleId(pair.Profile); bool wildcard = (suggestion != null) && suggestion.EndsWith("*", StringComparison.Ordinal); if (wildcard || identity.Profile == null) { identity.Profile = pair.Profile; identity.SigningKey = pair.SigningKey; identity.BundleId = GetDefaultBundleId(AppBundleName, suggestion); identity.AppId = ConstructValidAppId(pair.Profile, identity.BundleId); } if (wildcard) { break; } } Log.LogWarning(null, null, null, AppManifest, 0, 0, 0, 0, "No bundle identifier specified. Using '{0}' to match an installed provisioning profile.", identity.BundleId); } if (identity.Profile != null && identity.AppId != null) { codesignCommonName = identity.SigningKey != null?SecKeychain.GetCertificateCommonName(identity.SigningKey) : null; provisioningProfileName = identity.Profile.Name; DetectedCodeSigningKey = identity.SigningKey?.Thumbprint; DetectedProvisioningProfile = identity.Profile.Uuid; DetectedBundleId = identity.BundleId; DetectedAppId = identity.AppId; ReportDetectedCodesignInfo(); } else { if (identity.SigningKey != null) { Log.LogError("Bundle identifier '{0}' does not match any installed provisioning profile for selected signing identity '{0}'.", identity.BundleId, identity.SigningKey); } else { Log.LogError("Bundle identifier '{0}' does not match any installed provisioning profile.", identity.BundleId); } } return(!Log.HasLoggedErrors); }