How can I create a PKCS12 p12 file with selfsigned certificate for DSA keypair in C#?

前端 未结 1 1682
故里飘歌
故里飘歌 2021-01-15 15:20

I need to generate my own DSA keypair and store it as a bundle of private key and certificate in .p12 file using C#.

This question

How do I create a PKCS12 .

1条回答
  •  伪装坚强ぢ
    2021-01-15 16:25

    Got interested by this and here is my little investigation. When you set PrivateKey of certificateDSA, .NET code does roughly this:

    byte[] numArray1 = ((ICspAsymmetricAlgorithm) certificateDSA.PublicKey.Key).ExportCspBlob(false);
    byte[] numArray2 = csp.ExportCspBlob(false);
    // And then those two blobs are compared byte by byte
    

    Those blobs are different starting at position 420 (they have length of 444). So something is wrong in csp parameters. It's not easy to compare raw bytes, so let's convert them to readable xml with:

    var xml1 = certificateDSA.PublicKey.Key.ToXmlString(false);
    var xml2 = csp.ToXmlString(false);
    

    What we will get is this:

     
        

    2arEQPD3/tKm7pJF1y4gN0/4WzSGfkgFwdmtmoUf/gHoXpdBetRH/5j98qo4k1ybePxM4om4y6n9vhxijocMw5LaeQPceGyNOEScWXXrNKAcUsK74klQmiPOoI2qI1zU5v2HrilKmkOELH81U8/Qmmjmg7ouOdOHqlZAxW9Sv8M=

    lzRdUtp56eZHIgxRemvdHciGIfc= Z/2T+jXvv0ZLswbuMd9DxrHldakJxZ8JNGRf1QzN09B2VO9WYAzUy0S+J8hbYQjP/jzWbmL5LaK57v+MUOmOHzFwNqfVMe9OUglUfF3nN990ur9hp6csu8+vCEQt3EoI8Wmh/b2yqhtKRN6U494vf33WKo1NCNQapB+iWVQ/egQ= ykcPXFIxWvYDDbbY05oD3hD6LsM5rk76FakUY8YiCo8ZwWbMIlQw+v5nOYS9vpQaZAzUqxx9OXIGSTUGItruTARkDqZ0nGKL0r94Zhog1Y0wU2AVKJh8Vjq/dLFyDDGZZsxBZtmI8TDyKGJbZqvzGbdGLhoRxRFmNi1fVsADv+U=

    2arEQPD3/tKm7pJF1y4gN0/4WzSGfkgFwdmtmoUf/gHoXpdBetRH/5j98qo4k1ybePxM4om4y6n9vhxijocMw5LaeQPceGyNOEScWXXrNKAcUsK74klQmiPOoI2qI1zU5v2HrilKmkOELH81U8/Qmmjmg7ouOdOHqlZAxW9Sv8M=

    lzRdUtp56eZHIgxRemvdHciGIfc= Z/2T+jXvv0ZLswbuMd9DxrHldakJxZ8JNGRf1QzN09B2VO9WYAzUy0S+J8hbYQjP/jzWbmL5LaK57v+MUOmOHzFwNqfVMe9OUglUfF3nN990ur9hp6csu8+vCEQt3EoI8Wmh/b2yqhtKRN6U494vf33WKo1NCNQapB+iWVQ/egQ= ykcPXFIxWvYDDbbY05oD3hD6LsM5rk76FakUY8YiCo8ZwWbMIlQw+v5nOYS9vpQaZAzUqxx9OXIGSTUGItruTARkDqZ0nGKL0r94Zhog1Y0wU2AVKJh8Vjq/dLFyDDGZZsxBZtmI8TDyKGJbZqvzGbdGLhoRxRFmNi1fVsADv+U= 1hiZoCQFivF9xDZdQEGue65oObA= Og==

    You see that original DSACryptoServiceProvider includes Seed and PgenCounter, while after generating certificate with Bouncy Castle, certificate's public key does not contain them. Those parameters are optional (in a sense that public key may not contain then), but if they are present, they should be present on both sides (private and public). How can we workaround this? Here is the code:

    using (DSACryptoServiceProvider csp = new DSACryptoServiceProvider(1024)) {
                var parameters = csp.ExportParameters(true);                
                var keypair = DotNetUtilities.GetDsaKeyPair(parameters);
                var gen = new X509V3CertificateGenerator();
                var CN = new X509Name("CN=" + "TEST");
                var SN = BigInteger.ProbablePrime(120, new Random());
                gen.SetSerialNumber(SN);
                gen.SetSubjectDN(CN);
                gen.SetIssuerDN(CN);
                gen.SetNotAfter(DateTime.Now.AddDays(1));
                gen.SetNotBefore(DateTime.Now.Subtract(new TimeSpan(7, 0, 0, 0)));
                gen.SetSignatureAlgorithm("sha1WithDSA");
                gen.SetPublicKey(keypair.Public);
                var newCert = gen.Generate(keypair.Private);
    
                var certificateDSA = new X509Certificate2(DotNetUtilities.ToX509Certificate(newCert));
                // added block
                parameters.Seed = new byte[20];
                unchecked {
                    parameters.Counter = (int) 0xFFFFFFFF;
                }
                csp.ImportParameters(parameters);
                // end of added block
                certificateDSA.PrivateKey = csp;
                StringBuilder builder = new StringBuilder();
    
                builder.AppendLine("-----BEGIN CERTIFICATE-----");
                builder.AppendLine(Convert.ToBase64String(certificateDSA.Export(X509ContentType.Pkcs12), Base64FormattingOptions.InsertLineBreaks));
                builder.AppendLine("-----END CERTIFICATE-----");
    
                string result = builder.ToString();                
            }
    

    What we do here is after generating everything, but before assigning private key to certificate, we "removing" seed and counter from DSACryptoServiceProvider parameters. This code does not throw errors and completes fine. Maybe there are some caveats in this workaround, but nevertheless it might be useful to futher investigating the issue, even if it not fixes it completely.

    0 讨论(0)
提交回复
热议问题