0

I'm using Process to execute a batch file which will generate certificate file.

The code works great when I execute other file (which contains openssl command). But when I execute a file which contains keytool command, it executed, but no file was generated.

I've:

  • Set UseShellExecute true.
  • Set WaitForExit(-1) and find the return was true, so it did executed.
  • I clicked that batch file manually, and the file generates right away, so the command was fine :(
  • BTW I'm using .Net Core MVC.

I can't find any error code anywhere, so I'm at my wits' end now.

Does anyone has a clue? Any help would be very appriciated!

success code(openssl):

I generate a p12 file (a certificate format) in that folder first, and it works fine.

private string Gen_P12(string domain, string pwd)
        {
            //generate folder
            string folder = @"D:\Temp\";
            if (!Directory.Exists(folder))
                Directory.CreateDirectory(folder);

            //generate bat(p12)
            string bat = "openssl.exe pkcs12 -export -inkey " + domain + ".key -in " + domain + ".cer -out " + domain + ".p12 -password pass:" + pwd +"\r\n";
            //download in folder
            var path = Path.Combine(folder, domain + "_P12.bat");
            using (FileStream fs = System.IO.File.Create(path))
            {
                byte[] content = new UTF8Encoding(true).GetBytes(bat);
                fs.Write(content, 0, content.Length);
            }

            Thread.Sleep(500);

            //execute
            ProcessStartInfo myBat = new ProcessStartInfo();
            string name = domain + "_P12.bat";
            myBat.FileName = name;
            myBat.WorkingDirectory = folder;
            myBat.UseShellExecute = true;
            //Process.Start(myBat);
            Process p = Process.Start(myBat);
            p.WaitForExit(-1);

            return folder;
        }

fail code(keytool):

Trying to use that P12 file and keytool command to generate a keystore (also a certificate format) but fail.

private string Gen_KS(string domain, string folder, string CA_domain, byte[] cer, string pwd)
        {
            //generate bat
            string bat = "keytool -importkeystore -srckeystore " + domain + ".p12 -srcstoretype PKCS12 -srcstorepass " + pwd + " -destkeystore " + domain + ".keystore -storepass " + pwd + "\r\n";
            var path = Path.Combine(folder, domain + "_KS.bat");

            using (FileStream fs = System.IO.File.Create(path))
            {
                byte[] content = new UTF8Encoding(true).GetBytes(bat);
                fs.Write(content, 0, content.Length);
            }

            Thread.Sleep(700);
     
            //execute
            ProcessStartInfo myBat = new ProcessStartInfo();
            myBat.WorkingDirectory = folder;
            string name = domain + "_KS.bat";
            myBat.FileName = name;
            myBat.UseShellExecute = true;
            Process p = Process.Start(myBat);
            var a = p.WaitForExit(-1);

            string route = folder + domain + ".keystore";
            return route;
        }

Thanks!

  • 1
    The following may be helpful: https://stackoverflow.com/questions/69791571/c-sharp-redirect-other-console-app-standardoutput-fail-if-i-wont-close-stardand/69792388#69792388 – Tu deschizi eu inchid Jan 20 '22 at 04:48
  • @user9938 My god I read the link again and suddenly came out some ideas!! (sorry for not fully following it cuz I can't understand what `if true, uses 'ShellExecute'` is) Now I solved it, thank you for the inspiration! I'll update the solution later. Thanks again! <3 – 亞鯉斯多德 Jan 20 '22 at 07:36
  • Looks like an [xy problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) question. Your requirement is to generate certificate, not launch a specific batch file, isn't it ? I'm quite sure there are plenty of cryptographic c# classes that can do the job, w/o relying on external command lines – Steve B Jan 20 '22 at 07:56
  • 1
    Is there a reason you're writing and executing batch files to execute an application instead of just executing that application directly? You could then use the [`ExitCode` property](https://learn.microsoft.com/dotnet/api/system.diagnostics.process.exitcode) to determine success or failure. That is, `using (Process p = Process.Start("openssl.exe", "pkcs12 -export ... ")) { p.WaitForExit(); if (p.ExitCode > 0) { /* Handle error */ } }`. Also, `File.WriteAllText(path, bat);` is an easier way to write a text file. – Lance U. Matthews Jan 20 '22 at 07:57
  • @SteveB I think it's not a cryptographic problem because when I click the bat file manually it works (successfully generated) as I mention above, so I guess that's a execute problem. Thanks for the reply! – 亞鯉斯多德 Jan 20 '22 at 08:26
  • @LanceU.Matthews Aww thanks for the tutorials, I'll try them later! (I do have no idea how to execute the application directly before I found the solution...... :( ) – 亞鯉斯多德 Jan 20 '22 at 08:34

1 Answers1

0

Thanks to @user9938, I solved the problem!

1. Brief conclusion: I need to process the bat as administrator.

(And I still don't get why only do the keytool command needs administrator rights)

2. Find the errors: (How to apply StanderError when UseShellExecute=true)

In fact we don't have to set it true to execute commands. Try this (replace execute section):

 Process process = new Process();
            try
            {
                process.StartInfo.UseShellExecute = false;
                process.StartInfo.CreateNoWindow = true;
                process.StartInfo.RedirectStandardInput = true;
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.RedirectStandardError = true;
                process.StartInfo.FileName = "cmd.exe";
                process.Start();
                process.StandardInput.WriteLine(bat); //command string, not the bat file 
                process.StandardInput.AutoFlush = true;
                process.StandardInput.WriteLine("exit");
                StreamReader reader = process.StandardError;
                string curLine = reader.ReadLine();
                reader.Close();
                process.WaitForExit();
                process.Close();
            }catch (Exception e){}

Check the value of curLine through Breakpoints, the error message was: "'keytool' is not recognized as an internal or external command, operable program or batch file".

3. How to solve it:

Just set the Verb attribute as "runas".

            //execute
            ProcessStartInfo myBat = new ProcessStartInfo();
            myBat.WorkingDirectory = folder;
            string name = domain + "_KS.bat";
            myBat.Verb = "runas";
            myBat.FileName = name;
            myBat.UseShellExecute = true;
            Process p = Process.Start(myBat);
            var a = p.WaitForExit(-1);

Done! Thank you user9938<3