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; }
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; 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; 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); }