private void ChooseKeyPairButton_Click(object sender, EventArgs e) { OpenDialog.Filter = ToolsHub.KeysFilter; if (OpenDialog.ShowDialog() == DialogResult.OK) { KeyPairFilenameBox.Text = OpenDialog.FileName; AsymmetricCipherKeyPair KeyPair = CryptoAdapter.LoadKeyPairFromDiskBouncy(KeyPairFilenameBox.Text); if (KeyPair == null) { MessageBox.Show("Unable to load key pair from disk, make sure it is in a supported format (xml or pkcs 12 key store)", Config.AppDisplayName, MessageBoxButtons.OK, MessageBoxIcon.Error); KeyPairFilenameBox.Text = ""; } } }
private void GenerateRequestButton_Click(object sender, EventArgs e) { if (EMailEditBox.Text == "") { MessageBox.Show("An Email address is required to generate a signing request", Config.AppDisplayName, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (CommonNameEditBox.Text == "") { MessageBox.Show("A common name is required to generate a signing request", Config.AppDisplayName, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } AsymmetricCipherKeyPair KeyPair = null; try { KeyPair = CryptoAdapter.LoadKeyPairFromDiskBouncy(KeyPairFilenameBox.Text); if (KeyPair == null) { throw new InvalidDataException(); } } catch (Exception) { MessageBox.Show("A public/private key pair is required to generate a signing request (failed to find or open specified key pair file)", Config.AppDisplayName, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } SaveDialog.FileName = "CertificateSigningRequest.csr"; SaveDialog.DefaultExt = "csr"; SaveDialog.Filter = ToolsHub.CertificateRequestFilter; SaveDialog.Title = "Generate Certificate Signing Request"; if (SaveDialog.ShowDialog() == DialogResult.OK) { string EffectiveBuildPath = (Program.GameName.Length > 0) ? Config.BuildDirectory : Path.GetFullPath("."); string TargetCertRequestFileName = SaveDialog.FileName; GenerateSigningRequestViaOpenSSL(TargetCertRequestFileName, KeyPair); //GenerateSigningRequestViaBouncyCastle(TargetCertRequestFileName, KeyPair); // Close this dialog Close(); } }
public static string FindCompatibleProvision(string CFBundleIdentifier, out bool bNameMatch, bool bCheckCert = true, bool bCheckIdentifier = true, bool bCheckDistro = true) { bNameMatch = false; // remap the gamename if necessary string GameName = Program.GameName; if (GameName == "UE4Game") { if (Config.ProjectFile.Length > 0) { GameName = Path.GetFileNameWithoutExtension(Config.ProjectFile); } } // ensure the provision directory exists if (!Directory.Exists(Config.ProvisionDirectory)) { Directory.CreateDirectory(Config.ProvisionDirectory); } if (Config.bProvision) { if (File.Exists(Config.ProvisionDirectory + "/" + Config.Provision)) { return(Config.ProvisionDirectory + "/" + Config.Provision); } } #region remove after we provide an install mechanism CacheMobileProvisions(); #endregion // cache the provision library Dictionary <string, MobileProvision> ProvisionLibrary = new Dictionary <string, MobileProvision>(); foreach (string Provision in Directory.EnumerateFiles(Config.ProvisionDirectory, "*.mobileprovision")) { MobileProvision p = MobileProvisionParser.ParseFile(Provision); ProvisionLibrary.Add(Provision, p); if (p.FileName.Contains(p.UUID) && !File.Exists(Path.Combine(Config.ProvisionDirectory, "UE4_" + p.UUID + ".mobileprovision"))) { File.Copy(Provision, Path.Combine(Config.ProvisionDirectory, "UE4_" + p.UUID + ".mobileprovision")); p = MobileProvisionParser.ParseFile(Path.Combine(Config.ProvisionDirectory, "UE4_" + p.UUID + ".mobileprovision")); ProvisionLibrary.Add(Path.Combine(Config.ProvisionDirectory, "UE4_" + p.UUID + ".mobileprovision"), p); } } Program.Log("Searching for mobile provisions that match the game '{0}' (distribution: {3}) with CFBundleIdentifier='{1}' in '{2}'", GameName, CFBundleIdentifier, Config.ProvisionDirectory, Config.bForDistribution); // check the cache for a provision matching the app id (com.company.Game) // First checking for a contains match and then for a wildcard match for (int Phase = -1; Phase < 3; ++Phase) { if (Phase == -1 && string.IsNullOrEmpty(Config.ProvisionUUID)) { continue; } foreach (KeyValuePair <string, MobileProvision> Pair in ProvisionLibrary) { string DebugName = Path.GetFileName(Pair.Key); MobileProvision TestProvision = Pair.Value; // make sure the file is not managed by Xcode if (Path.GetFileName(TestProvision.FileName).ToLower().Equals(TestProvision.UUID.ToLower() + ".mobileprovision")) { continue; } Program.LogVerbose(" Phase {0} considering provision '{1}' named '{2}'", Phase, DebugName, TestProvision.ProvisionName); if (TestProvision.ProvisionName == "iOS Team Provisioning Profile: " + CFBundleIdentifier) { Program.LogVerbose(" Failing as provisioning is automatic"); continue; } // check to see if the platform is the same as what we are looking for if (!string.IsNullOrEmpty(TestProvision.Platform) && TestProvision.Platform != Config.OSString && !string.IsNullOrEmpty(Config.OSString)) { //Program.LogVerbose(" Failing platform {0} Config: {1}", TestProvision.Platform, Config.OSString); continue; } // Validate the name bool bPassesNameCheck = false; if (Phase == -1) { bPassesNameCheck = TestProvision.UUID == Config.ProvisionUUID; bNameMatch = bPassesNameCheck; } else if (Phase == 0) { bPassesNameCheck = TestProvision.ApplicationIdentifier.Substring(TestProvision.ApplicationIdentifierPrefix.Length + 1) == CFBundleIdentifier; bNameMatch = bPassesNameCheck; } else if (Phase == 1) { if (TestProvision.ApplicationIdentifier.Contains("*")) { string CompanyName = TestProvision.ApplicationIdentifier.Substring(TestProvision.ApplicationIdentifierPrefix.Length + 1); if (CompanyName != "*") { CompanyName = CompanyName.Substring(0, CompanyName.LastIndexOf(".")); bPassesNameCheck = CFBundleIdentifier.StartsWith(CompanyName); } } } else { if (TestProvision.ApplicationIdentifier.Contains("*")) { string CompanyName = TestProvision.ApplicationIdentifier.Substring(TestProvision.ApplicationIdentifierPrefix.Length + 1); bPassesNameCheck = CompanyName == "*"; } } if (!bPassesNameCheck && bCheckIdentifier) { Program.LogVerbose(" .. Failed phase {0} name check (provision app ID was {1})", Phase, TestProvision.ApplicationIdentifier); continue; } if (Config.bForDistribution) { // Check to see if this is a distribution provision. get-task-allow must be false for distro profiles. // TestProvision.ProvisionedDeviceIDs.Count==0 is not a valid check as ad-hoc distro profiles do list devices. bool bDistroProv = !TestProvision.bDebug; if (!bDistroProv) { Program.LogVerbose(" .. Failed distribution check (mode={0}, get-task-allow={1}, #devices={2})", Config.bForDistribution, TestProvision.bDebug, TestProvision.ProvisionedDeviceIDs.Count); continue; } } else { if (bCheckDistro) { bool bPassesDebugCheck = TestProvision.bDebug; if (!bPassesDebugCheck) { Program.LogVerbose(" .. Failed debugging check (mode={0}, get-task-allow={1}, #devices={2})", Config.bForDistribution, TestProvision.bDebug, TestProvision.ProvisionedDeviceIDs.Count); continue; } } else { if (!TestProvision.bDebug) { Config.bForceStripSymbols = true; } } } // Check to see if the provision is in date DateTime CurrentUTCTime = DateTime.UtcNow; bool bPassesDateCheck = (CurrentUTCTime >= TestProvision.CreationDate) && (CurrentUTCTime < TestProvision.ExpirationDate); if (!bPassesDateCheck) { Program.LogVerbose(" .. Failed time period check (valid from {0} to {1}, but UTC time is now {2})", TestProvision.CreationDate, TestProvision.ExpirationDate, CurrentUTCTime); continue; } // check to see if we have a certificate for this provision bool bPassesHasMatchingCertCheck = false; if (bCheckCert) { X509Certificate2 Cert = CodeSignatureBuilder.FindCertificate(TestProvision); bPassesHasMatchingCertCheck = (Cert != null); if (bPassesHasMatchingCertCheck && Config.bCert) { bPassesHasMatchingCertCheck &= (CryptoAdapter.GetFriendlyNameFromCert(Cert) == Config.Certificate); } } else { bPassesHasMatchingCertCheck = true; } if (!bPassesHasMatchingCertCheck) { Program.LogVerbose(" .. Failed to find a matching certificate that was in date"); continue; } // Made it past all the tests Program.LogVerbose(" Picked '{0}' with AppID '{1}' and Name '{2}' as a matching provision for the game '{3}'", DebugName, TestProvision.ApplicationIdentifier, TestProvision.ProvisionName, GameName); return(Pair.Key); } } // check to see if there is already an embedded provision string EmbeddedMobileProvisionFilename = Path.Combine(Config.RepackageStagingDirectory, "embedded.mobileprovision"); Program.Warning("Failed to find a valid matching mobile provision, will attempt to use the embedded mobile provision instead if present"); return(EmbeddedMobileProvisionFilename); }
/// <summary> /// Prepares this signer to sign an application /// Modifies the following files: /// embedded.mobileprovision /// </summary> public void PrepareForSigning() { // Load Info.plist, which guides nearly everything else Info = LoadInfoPList(); // Get the name of the bundle string CFBundleIdentifier; if (!Info.GetString("CFBundleIdentifier", out CFBundleIdentifier)) { throw new InvalidDataException("Info.plist must contain the key CFBundleIdentifier"); } // Load the mobile provision, which provides entitlements and a partial cert which can be used to find an installed certificate LoadMobileProvision(CFBundleIdentifier); if (Provision == null) { return; } // Install the Apple trust chain certs (required to do a CMS signature with full chain embedded) List <string> TrustChainCertFilenames = new List <string>(); string CertPath = Path.GetFullPath(Config.EngineBuildDirectory); TrustChainCertFilenames.Add(Path.Combine(CertPath, "AppleWorldwideDeveloperRelationsCA.pem")); TrustChainCertFilenames.Add(Path.Combine(CertPath, "AppleRootCA.pem")); InstallCertificates(TrustChainCertFilenames); // Find and load the signing cert SigningCert = LoadSigningCertificate(); if (SigningCert == null) { // Failed to find a cert already installed or to install, cannot proceed any futher Program.Error("... Failed to find a certificate that matches the mobile provision to be used for code signing"); Program.ReturnCode = (int)ErrorCodes.Error_CertificateNotFound; throw new InvalidDataException("Certificate not found!"); } else { Program.Log("... Found matching certificate '{0}' (valid from {1} to {2})", CryptoAdapter.GetFriendlyNameFromCert(SigningCert), SigningCert.GetEffectiveDateString(), SigningCert.GetExpirationDateString()); } }
/// <summary> /// Finds all valid installed provisions /// </summary> public static void FindProvisions(string CFBundleIdentifier) { if (!Directory.Exists(Config.ProvisionDirectory)) { Program.Error("Could not find provision directory '{0}'.", Config.ProvisionDirectory); Program.ReturnCode = (int)ErrorCodes.Error_ProvisionNotFound; return; } // cache the provision library string SelectedProvision = ""; string SelectedCert = ""; string SelectedFile = ""; int FoundName = -1; Dictionary <string, MobileProvision> ProvisionLibrary = new Dictionary <string, MobileProvision>(); foreach (string Provision in Directory.EnumerateFiles(Config.ProvisionDirectory, "*.mobileprovision")) { MobileProvision p = MobileProvisionParser.ParseFile(Provision); DateTime EffectiveDate = p.CreationDate; DateTime ExpirationDate = p.ExpirationDate; DateTime Now = DateTime.UtcNow; bool bCertTimeIsValid = (EffectiveDate < Now) && (ExpirationDate > Now); bool bValid = false; X509Certificate2 Cert = FindCertificate(p); if (Cert != null) { bValid = (Cert.NotBefore.ToUniversalTime() < Now) && (Cert.NotAfter.ToUniversalTime() > Now); } bool bPassesNameCheck = p.ApplicationIdentifier.Substring(p.ApplicationIdentifierPrefix.Length + 1) == CFBundleIdentifier; bool bPassesCompanyCheck = false; bool bPassesWildCardCheck = false; if (p.ApplicationIdentifier.Contains("*")) { string CompanyName = p.ApplicationIdentifier.Substring(p.ApplicationIdentifierPrefix.Length + 1); if (CompanyName != "*") { CompanyName = CompanyName.Substring(0, CompanyName.LastIndexOf(".")); bPassesCompanyCheck = CFBundleIdentifier.StartsWith(CompanyName); } else { bPassesWildCardCheck = true; } } bool bIsManaged = false; if (p.ProvisionName == "iOS Team Provisioning Profile: " + CFBundleIdentifier) { bIsManaged = true; } bool bDistribution = ((p.ProvisionedDeviceIDs.Count == 0) && !p.bDebug); string Validity = "VALID"; if (!bCertTimeIsValid) { Validity = "EXPIRED"; } else if (!bValid) { Validity = "NO_CERT"; } else if (!bPassesNameCheck && !bPassesWildCardCheck && !bPassesCompanyCheck) { Validity = "NO_MATCH"; } if (bIsManaged) { Validity = "MANAGED"; } if ((string.IsNullOrWhiteSpace(SelectedProvision) || FoundName < 2) && Validity == "VALID" && !bDistribution) { int Prev = FoundName; if (bPassesNameCheck) { FoundName = 2; } else if (bPassesCompanyCheck && FoundName < 1) { FoundName = 1; } else if (bPassesWildCardCheck && FoundName == -1) { FoundName = 0; } if (FoundName != Prev) { SelectedProvision = p.ProvisionName; SelectedFile = Path.GetFileName(Provision); SelectedCert = CryptoAdapter.GetFriendlyNameFromCert(Cert); } } Program.LogVerbose("PROVISION-File:{0},Name:{1},Validity:{2},StartDate:{3},EndDate:{4},Type:{5}", Path.GetFileName(Provision), p.ProvisionName, Validity, EffectiveDate.ToString(), ExpirationDate.ToString(), bDistribution ? "DISTRIBUTION" : "DEVELOPMENT"); } Program.LogVerbose("MATCHED-Provision:{0},File:{1},Cert:{2}", SelectedProvision, SelectedFile, SelectedCert); }
/// <summary> /// Tries to find a matching certificate on this machine from the the serial number of one of the /// certificates in the mobile provision (the one in the mobileprovision is missing the public/private key pair) /// </summary> public static X509Certificate2 FindCertificate(MobileProvision ProvisionToWorkFrom) { Program.LogVerbose(" Looking for a certificate that matches the application identifier '{0}'", ProvisionToWorkFrom.ApplicationIdentifier); X509Certificate2 Result = null; if (Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX) { // run certtool y to get the currently installed certificates CertToolData = ""; Process CertTool = new Process(); CertTool.StartInfo.FileName = "/usr/bin/security"; CertTool.StartInfo.UseShellExecute = false; CertTool.StartInfo.Arguments = "find-identity -p codesigning -v"; CertTool.StartInfo.RedirectStandardOutput = true; CertTool.OutputDataReceived += new DataReceivedEventHandler(OutputReceivedCertToolProcessCall); CertTool.Start(); CertTool.BeginOutputReadLine(); CertTool.WaitForExit(); if (CertTool.ExitCode == 0) { foreach (X509Certificate2 SourceCert in ProvisionToWorkFrom.DeveloperCertificates) { X509Certificate2 ValidInTimeCert = null; // see if certificate can be found by serial number string CertHash = SourceCert.GetCertHashString(); if (CertToolData.Contains(CertHash)) { ValidInTimeCert = SourceCert; } if (ValidInTimeCert != null) { // Found a cert in the valid time range, quit now! Result = ValidInTimeCert; break; } } } } else { // Open the personal certificate store on this machine X509Store Store = new X509Store(); Store.Open(OpenFlags.ReadOnly); // Try finding a matching certificate from the serial number (the one in the mobileprovision is missing the public/private key pair) foreach (X509Certificate2 SourceCert in ProvisionToWorkFrom.DeveloperCertificates) { X509Certificate2Collection FoundCerts = Store.Certificates.Find(X509FindType.FindBySerialNumber, SourceCert.SerialNumber, false); Program.LogVerbose(" .. Provision entry SN '{0}' matched {1} installed certificate(s)", SourceCert.SerialNumber, FoundCerts.Count); X509Certificate2 ValidInTimeCert = null; foreach (X509Certificate2 TestCert in FoundCerts) { DateTime EffectiveDate = TestCert.NotBefore.ToUniversalTime(); DateTime ExpirationDate = TestCert.NotAfter.ToUniversalTime(); DateTime Now = DateTime.UtcNow; bool bCertTimeIsValid = (EffectiveDate < Now) && (ExpirationDate > Now); Program.LogVerbose(" .. .. Installed certificate '{0}' is {1} (range '{2}' to '{3}')", CryptoAdapter.GetFriendlyNameFromCert(TestCert), bCertTimeIsValid ? "valid (choosing it)" : "EXPIRED", TestCert.GetEffectiveDateString(), TestCert.GetExpirationDateString()); if (bCertTimeIsValid) { ValidInTimeCert = TestCert; break; } } if (ValidInTimeCert != null) { // Found a cert in the valid time range, quit now! Result = ValidInTimeCert; break; } } Store.Close(); } if (Result == null) { Program.LogVerbose(" .. Failed to find a valid certificate that was in date"); } return(Result); }
/// <summary> /// Finds all valid installed certificates /// </summary> public static void FindCertificates() { string[] ValidCertificatePrefixes = { "iPhone Developer", "iPhone Distribution", "Apple Development", "Apple Distribution" }; X509Certificate2Collection FoundCerts = new X509Certificate2Collection(); if (Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX) { foreach (string SearchPrefix in ValidCertificatePrefixes) { // run certtool y to get the currently installed certificates CertToolData = ""; Process CertTool = new Process(); CertTool.StartInfo.FileName = "/usr/bin/security"; CertTool.StartInfo.UseShellExecute = false; CertTool.StartInfo.Arguments = string.Format("find-certificate -a -c \"{0}\" -p", SearchPrefix); CertTool.StartInfo.RedirectStandardOutput = true; CertTool.OutputDataReceived += new DataReceivedEventHandler(OutputReceivedCertToolProcessCall); CertTool.Start(); CertTool.BeginOutputReadLine(); CertTool.WaitForExit(); if (CertTool.ExitCode == 0) { string header = "-----BEGIN CERTIFICATE-----\n"; string footer = "-----END CERTIFICATE-----"; int start = CertToolData.IndexOf(header); while (start != -1) { start += header.Length; int end = CertToolData.IndexOf(footer, start); string base64 = CertToolData.Substring(start, (end - start)); byte[] certData = Convert.FromBase64String(base64); X509Certificate2 cert = new X509Certificate2(certData); FoundCerts.Add(cert); start = CertToolData.IndexOf(header, start); } } } } else { // Open the personal certificate store on this machine X509Store Store = new X509Store(); Store.Open(OpenFlags.ReadOnly); foreach (string SearchPrefix in ValidCertificatePrefixes) { FoundCerts.AddRange(Store.Certificates.Find(X509FindType.FindBySubjectName, SearchPrefix, false)); } Store.Close(); } foreach (X509Certificate2 TestCert in FoundCerts) { DateTime EffectiveDate = TestCert.NotBefore.ToUniversalTime(); DateTime ExpirationDate = TestCert.NotAfter.ToUniversalTime(); DateTime Now = DateTime.UtcNow; bool bCertTimeIsValid = (EffectiveDate < Now) && (ExpirationDate > Now); Program.LogVerbose("CERTIFICATE-Name:{0},Validity:{1},StartDate:{2},EndDate:{3}", CryptoAdapter.GetFriendlyNameFromCert(TestCert), bCertTimeIsValid ? "VALID" : "EXPIRED", EffectiveDate.ToString("o"), ExpirationDate.ToString("o")); } }
public static void TryInstallingCertificate_PromptForKey(string CertificateFilename, bool ShowPrompt = true) { try { if (!String.IsNullOrEmpty(CertificateFilename) || ShowOpenFileDialog(CertificatesFilter, "Choose a code signing certificate to import", "", "", ref ChoosingFilesToInstallDirectory, out CertificateFilename)) { if (Environment.OSVersion.Platform == PlatformID.MacOSX || Environment.OSVersion.Platform == PlatformID.Unix) { // run certtool y to get the currently installed certificates CertToolData = ""; Process CertTool = new Process(); CertTool.StartInfo.FileName = "/usr/bin/security"; CertTool.StartInfo.UseShellExecute = false; CertTool.StartInfo.Arguments = "import \"" + CertificateFilename + "\" -k login.keychain"; CertTool.StartInfo.RedirectStandardOutput = true; CertTool.OutputDataReceived += new DataReceivedEventHandler(OutputReceivedCertToolProcessCall); CertTool.Start(); CertTool.BeginOutputReadLine(); CertTool.WaitForExit(); if (CertTool.ExitCode != 0) { // todo: provide some feedback that it failed } Console.Write(CertToolData); } else { // Load the certificate string CertificatePassword = ""; X509Certificate2 Cert = null; try { Cert = new X509Certificate2(CertificateFilename, CertificatePassword, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet); } catch (System.Security.Cryptography.CryptographicException ex) { // Try once with a password if (PasswordDialog.RequestPassword(out CertificatePassword)) { Cert = new X509Certificate2(CertificateFilename, CertificatePassword, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet); } else { // User cancelled dialog, rethrow throw ex; } } // If the certificate doesn't have a private key pair, ask the user to provide one if (!Cert.HasPrivateKey) { string ErrorMsg = "Certificate does not include a private key and cannot be used to code sign"; // Prompt for a key pair if (MessageBox(new IntPtr(0), "Next, please choose the key pair that you made when generating the certificate request.", Config.AppDisplayName, 0x00000000 | 0x00000040 | 0x00001000 | 0x00010000) == 1) { string KeyFilename; if (ShowOpenFileDialog(KeysFilter, "Choose the key pair that belongs with the signing certificate", "", "", ref ChoosingFilesToInstallDirectory, out KeyFilename)) { Cert = CryptoAdapter.CombineKeyAndCert(CertificateFilename, KeyFilename); if (Cert.HasPrivateKey) { ErrorMsg = null; } } } if (ErrorMsg != null) { throw new Exception(ErrorMsg); } } // Add the certificate to the store X509Store Store = new X509Store(); Store.Open(OpenFlags.ReadWrite); Store.Add(Cert); Store.Close(); } } } catch (Exception ex) { string ErrorMsg = String.Format("Failed to load or install certificate due to an error: '{0}'", ex.Message); Program.Error(ErrorMsg); System.Threading.Thread.Sleep(500); MessageBox(new IntPtr(0), ErrorMsg, Config.AppDisplayName, 0x00000000 | 0x00000010 | 0x00001000 | 0x00010000); } }
public static bool IsProfileForDistribution(MobileProvision Provision) { return(CryptoAdapter.GetCommonNameFromCert(Provision.DeveloperCertificates[0]).IndexOf("iPhone Distribution", StringComparison.InvariantCultureIgnoreCase) >= 0); }
static int Main(string[] args) { // remember the working directory at start, as the game path could be relative to this path string InitialCurrentDirectory = Environment.CurrentDirectory; // set the working directory to the location of the application (so relative paths always work) Environment.CurrentDirectory = Path.GetDirectoryName(Application.ExecutablePath); AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); // A simple, top-level try-catch block try { if (!ParseCommandLine(ref args)) { Log("Usage: iPhonePackager <Command> <GameName> [RPCCommand &| Switch]"); Log(""); Log("Common commands:"); Log(" ... RepackageIPA GameName"); Log(" ... PackageIPA GameName"); Log(" ... PackageApp GameName"); Log(" ... Deploy PathToIPA"); Log(" ... RepackageFromStage GameName"); Log(" ... Devices"); Log(" ... Validate"); Log(" ... Install"); Log(""); Log("Configuration switches:"); Log(" -stagedir <path> sets the directory to copy staged files from (defaults to none)"); Log(" -project <path> path to the project being packaged"); Log(" -provisioning <uuid> uuid of the provisioning selected"); Log(" -compress=fast|best|none packaging compression level (defaults to none)"); Log(" -strip strip symbols during packaging"); Log(" -config game configuration (e.g., Shipping, Development, etc...)"); Log(" -distribution packaging for final distribution"); Log(" -codebased packaging a c++ code based project"); Log(" -createstub packaging stub IPA for later repackaging"); Log(" -mac <MacName> overrides the machine to use for any Mac operations"); Log(" -arch <Architecture> sets the architecture to use (blank for default, -simulator for simulator builds)"); Log(" -device <DeviceID> sets the device to install the IPA on"); Log(""); Log("Commands: RPC, Clean"); Log(" StageMacFiles, GetIPA, Deploy, Install, Uninstall"); Log(""); Log("RPC Commands: SetExec, InstallProvision, MakeApp, DeleteIPA, Copy, Kill, Strip, Zip, GenDSYM"); Log(""); Log("Sample commandlines:"); Log(" ... iPhonePackager Deploy UDKGame Release"); Log(" ... iPhonePackager RPC SwordGame Shipping MakeApp"); return((int)ErrorCodes.Error_Arguments); } Log("Executing iPhonePackager " + String.Join(" ", args)); Log("CWD: " + Directory.GetCurrentDirectory()); Log("Initial Dir: " + InitialCurrentDirectory); Log("Env CWD: " + Environment.CurrentDirectory); // Ensure shipping configuration for final distributions if (Config.bForDistribution && (GameConfiguration != "Shipping")) { Program.Warning("Distribution builds should be made in the Shipping configuration!"); } // process the GamePath (if could be ..\Samples\MyDemo\ or ..\Samples\MyDemo\MyDemo.uproject GameName = Path.GetFileNameWithoutExtension(GamePath); if (GameName.Equals("UE4", StringComparison.InvariantCultureIgnoreCase) || GameName.Equals("Engine", StringComparison.InvariantCultureIgnoreCase)) { GameName = "UE4Game"; } // setup configuration if (!Config.Initialize(InitialCurrentDirectory, GamePath)) { return((int)ErrorCodes.Error_Arguments); } switch (MainCommand.ToLowerInvariant()) { case "validate": // check to see if iTunes is installed string dllPath = ""; if (Environment.OSVersion.Platform == PlatformID.MacOSX || Environment.OSVersion.Platform == PlatformID.Unix) { ProcessStartInfo StartInfo = new ProcessStartInfo("/usr/bin/xcode-select", "--print-path"); StartInfo.UseShellExecute = false; StartInfo.RedirectStandardOutput = true; StartInfo.CreateNoWindow = true; using (Process LocalProcess = Process.Start(StartInfo)) { StreamReader OutputReader = LocalProcess.StandardOutput; // trim off any extraneous new lines, helpful for those one-line outputs dllPath = OutputReader.ReadToEnd().Trim(); } } else { dllPath = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Apple Inc.\\Apple Mobile Device Support\\Shared", "iTunesMobileDeviceDLL", null) as string; if (String.IsNullOrEmpty(dllPath) || !File.Exists(dllPath)) { dllPath = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Apple Inc.\\Apple Mobile Device Support\\Shared", "MobileDeviceDLL", null) as string; if (String.IsNullOrEmpty(dllPath) || !File.Exists(dllPath)) { dllPath = FindWindowsStoreITunesDLL(); } } } if (String.IsNullOrEmpty(dllPath) || (!File.Exists(dllPath) && !Directory.Exists(dllPath))) { Error("iTunes Not Found!!", (int)ErrorCodes.Error_SDKNotFound); } else { // validate there is a useable provision and cert MobileProvision Provision; X509Certificate2 Cert; bool bHasOverrides; bool bNameMatch; bool foundPlist = CodeSignatureBuilder.FindRequiredFiles(out Provision, out Cert, out bHasOverrides, out bNameMatch); if (!foundPlist) { Error("Could not find a valid plist file!!", (int)ErrorCodes.Error_InfoPListNotFound); } else if (!Config.bAutomaticSigning) { if (Provision == null && Cert == null) { Error("No Provision or cert found!!", (int)ErrorCodes.Error_ProvisionAndCertificateNotFound); } else if (Provision == null) { Error("No Provision found!!", (int)ErrorCodes.Error_ProvisionNotFound); } else if (Cert == null) { Error("No Signing Certificate found!!", (int)ErrorCodes.Error_CertificateNotFound); } } else { if (Config.TeamID == null) { Error("No TeamID for automatic signing!!", (int)ErrorCodes.Error_ProvisionNotFound); } } } break; case "packageapp": if (CheckArguments()) { if (Config.bCreateStubSet) { Error("packageapp cannot be used with the -createstub switch"); Program.ReturnCode = (int)ErrorCodes.Error_Arguments; } else { // Create the .app on the Mac CompileTime.CreateApplicationDirOnMac(); } } break; case "repackagefromstage": if (CheckArguments()) { if (Config.bCreateStubSet) { Error("repackagefromstage cannot be used with the -createstub switches"); Program.ReturnCode = (int)ErrorCodes.Error_Arguments; } else { bool bProbablyCreatedStub = Utilities.GetEnvironmentVariable("ue.IOSCreateStubIPA", true); if (!bProbablyCreatedStub) { Warning("ue.IOSCreateStubIPA is currently FALSE, which means you may be repackaging with an out of date stub IPA!"); } CookTime.RepackageIPAFromStub(); } } break; // this is the "super fast just move executable" mode for quick programmer iteration case "dangerouslyfast": if (CheckArguments()) { CompileTime.DangerouslyFastMode(); } break; case "packageipa": if (CheckArguments()) { CompileTime.PackageIPAOnMac(); } break; case "install": GameName = ""; if (Config.bProvision) { ToolsHub.TryInstallingMobileProvision(Config.Provision, false); } if (Config.bCert) { ToolsHub.TryInstallingCertificate_PromptForKey(Config.Certificate, false); } CodeSignatureBuilder.FindCertificates(); CodeSignatureBuilder.FindProvisions(Config.OverrideBundleName); break; case "certificates": { CodeSignatureBuilder.FindCertificates(); CodeSignatureBuilder.FindProvisions(Config.OverrideBundleName); } break; case "resigntool": RunInVisualMode(delegate { return(new GraphicalResignTool()); }); break; case "certrequest": RunInVisualMode(delegate { return(new GenerateSigningRequestDialog()); }); break; case "gui": RunInVisualMode(delegate { return(ToolsHub.CreateShowingTools()); }); break; case "devices": ListDevices(); break; case "signing_match": { MobileProvision Provision; X509Certificate2 Cert; bool bNameMatch; bool bHasOverrideFile; MobileProvision.CacheMobileProvisions(); if (CodeSignatureBuilder.FindRequiredFiles(out Provision, out Cert, out bHasOverrideFile, out bNameMatch) && Cert != null) { // print out the provision and cert name Program.LogVerbose("CERTIFICATE-{0},PROVISION-{1}", CryptoAdapter.GetFriendlyNameFromCert(Cert), Provision.FileName); } else { Program.LogVerbose("No matching Signing Data found!"); } } break; default: // Commands by themself default to packaging for the device if (CheckArguments()) { ExecuteCommand(MainCommand, MainRPCCommand); } break; } } catch (Exception Ex) { Error("Application exception: " + Ex.ToString()); if (ReturnCode == 0) { Program.ReturnCode = (int)ErrorCodes.Error_Unknown; } } finally { if (DeploymentHelper.DeploymentServerProcess != null) { DeploymentHelper.DeploymentServerProcess.Close(); } } Environment.ExitCode = ReturnCode; return(ReturnCode); }
public static void TryInstallingCertificate_PromptForKey() { try { string CertificateFilename; if (ShowOpenFileDialog(CertificatesFilter, "Choose a code signing certificate to import", "", "", ref ChoosingFilesToInstallDirectory, out CertificateFilename)) { // Load the certificate string CertificatePassword = ""; X509Certificate2 Cert = null; try { Cert = new X509Certificate2(CertificateFilename, CertificatePassword, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet); } catch (System.Security.Cryptography.CryptographicException ex) { // Try once with a password if (PasswordDialog.RequestPassword(out CertificatePassword)) { Cert = new X509Certificate2(CertificateFilename, CertificatePassword, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet); } else { // User cancelled dialog, rethrow throw ex; } } // If the certificate doesn't have a private key pair, ask the user to provide one if (!Cert.HasPrivateKey) { string ErrorMsg = "Certificate does not include a private key and cannot be used to code sign"; // Prompt for a key pair if (MessageBox.Show("Next, please choose the key pair that you made when generating the certificate request.", Config.AppDisplayName, MessageBoxButtons.OK, MessageBoxIcon.Information) == DialogResult.OK) { string KeyFilename; if (ShowOpenFileDialog(KeysFilter, "Choose the key pair that belongs with the signing certificate", "", "", ref ChoosingFilesToInstallDirectory, out KeyFilename)) { Cert = CryptoAdapter.CombineKeyAndCert(CertificateFilename, KeyFilename); if (Cert.HasPrivateKey) { ErrorMsg = null; } } } if (ErrorMsg != null) { throw new Exception(ErrorMsg); } } // Add the certificate to the store X509Store Store = new X509Store(); Store.Open(OpenFlags.ReadWrite); Store.Add(Cert); Store.Close(); } } catch (Exception ex) { string ErrorMsg = String.Format("Failed to load or install certificate due to an error: '{0}'", ex.Message); Program.Error(ErrorMsg); MessageBox.Show(ErrorMsg, Config.AppDisplayName, MessageBoxButtons.OK, MessageBoxIcon.Error); } }