1

I'm developing an API server that will take input from user for following information

"CN=ABC123,O=DEF,L=XYZ,S=CA,C=US,E=info@abc.com"

and create a signed developer's certificate using our root certificate. For making certificates using makecert.exe I've followed Creating self signed certificates with makecert.exe for development tutorial and created root certificate using following commands

makecert.exe ^
-n "CN=CARoot" ^
-r ^
-pe ^
-a sha512 ^
-len 4096 ^
-cy authority ^
-sv CARoot.pvk ^
CARoot.cer

pvk2pfx.exe ^
-pvk CARoot.pvk ^
-spc CARoot.cer ^
-pfx CARoot.pfx ^
-po Test123

in command prompt and it asks for certificate and private.key passwords in a prompt popup that is fine since this is one time process and I have done this manually

Where as for developers certificate I have used

Process.Start("makecert.exe",certCmd);

with the following in certCmd as string

makecert.exe ^
-n "CN=%1" ^
-iv CARoot.pvk ^
-ic CARoot.cer ^
-pe ^
-a sha512 ^
-len 4096 ^
-b 01/01/2014 ^
-e 01/01/2016 ^
-sky exchange ^
-eku 1.3.6.1.5.5.7.3.2 ^
-sv %1.pvk ^
%1.cer

pvk2pfx.exe ^
-pvk %1.pvk ^
-spc %1.cer ^
-pfx %1.pfx ^
-po Test123

now according to the documentation there is no -po parameter that is given in the above command and as a result it asks for password in the prompt that is an issue here

since this is an API and there will be no way to input the password in the prompt for private key

The other option is to use X509Certificate2 and bouncyCastle but not sure how to use them, any help will be appreciable

I want to keep it as simple as possible and that is the reason I went for makecert.exewith Process.Start()

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
riksof-zeeshan
  • 531
  • 9
  • 27

3 Answers3

2

If you want to produce your own certificates... I have used this code in the past to generate certificates on the fly. You will need to adjust it for your solution but it should give you everything you need. It uses Bouncy Castle.

public static X509Certificate GenerateRootCertificate(AsymmetricCipherKeyPair key, X509Name subjectAndIssuer, int serialNumber, int yearsValid)
    {
        X509V3CertificateGenerator gen = new X509V3CertificateGenerator();
        Asn1SignatureFactory sig = new Asn1SignatureFactory("SHA256withRSA", key.Private, new SecureRandom());
        DateTime notBefore = DateTime.Now;
        DateTime notAfter = DateTime.Now.AddYears(yearsValid);

        gen.SetSerialNumber(BigInteger.ValueOf(serialNumber));
        gen.SetSubjectDN(subjectAndIssuer);
        gen.SetIssuerDN(subjectAndIssuer);
        gen.SetPublicKey(key.Public);

        gen.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(true));
        gen.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.DigitalSignature | KeyUsage.CrlSign | KeyUsage.KeyCertSign));
        gen.AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifierStructure(key.Public));
        gen.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(key.Public));

        gen.SetNotBefore(notBefore);
        gen.SetNotAfter(notAfter);

        return gen.Generate(sig);
    }

This would probably be a better way to go about it, gives you more control in the end.

EDIT: You can retrieve your public and private key by using this method, given that it is in PEM format:

public static object ReadObjectFromPEMFile(string fileName)
        {
            PemReader reader = new PemReader(new StreamReader(File.Open(fileName, FileMode.Open)));
            object r = reader.ReadObject();
            reader.Reader.Close();
            return r;
        }

Don't forget to cast the result to AsymmetricCipherKeyPair!

Luke Joshua Park
  • 9,527
  • 5
  • 27
  • 44
1

I agree with @LukeParks answer, that you should do that all in your own code, but if you still want to go with you current way, here is how:

You can redirect the StandardInput of the makecert process to pass the input directly to the program.

ProcessStartInfo procInf = new ProcessStartInfo("makecert.exe",certCmd)
{
    RedirectStandardOutput = true,
    RedirectStandardInput = true,
    RedirectStandardError = true,
    UseShellExecute = false,
    CreateNoWindow = true
};

Process makeCertProcess = Process.Start(procInf);

//Here is the "manual" input (timing doesn't matter)
pscp.StandardInput.WriteLine("password or whatever");

pscp.WaitForExit(TimeOut);

string errors = pscp.StandardError.ReadToEnd();
string output = pscp.StandardOutput.ReadToEnd();
int errorcode = pscp.ExitCode;
Manfred Radlwimmer
  • 13,257
  • 13
  • 53
  • 62
0

I have answered a very similar question some time ago. The question then was to

Generate self signed certificate on the fly

but later the question was modified to issue end entity certificates using before generated CA certificate. Hmm, it seems I have not renamed the method GenerateSelfSignedCertificate after the change. It should be named GenerateEndEntityCertificate because that's what it does.

Try to look at my answer here

Community
  • 1
  • 1
pepo
  • 8,644
  • 2
  • 27
  • 42