11

In order to access to the web service I need a certificate.

I generated my certs:

openssl genrsa 1024 > private.key
openssl req -new -x509 -nodes -sha1 -days 1100 -key private.key > public.cer

then merged this two into a pfx certificate by

openssl pkcs12 -in public.cer -inkey private.key -export -out client.pfx

then loaded my pfx file as X509Certificate2

X509Certificate2 clientCert = new X509Certificate2("cert.pfx", "password");

Now, I would like to create a table into the data base that contains the following fields:

PrivateKey NVARCHAR  
PublicCer NVARCHAR  
Password NVARCHAR  

Then copy the content from private.key file, along with -----BEGIN CERTIFICATE----- and -----END CERTIFICATE-----, same for the public.cer, and set the password. Now, how can I get a proper instance of X509Certificate2 by reading this data from DB? In other words, how can I generate a pfx file from code, based on private key and certificate?

I will try to be more precise:

 string connectionString; string query; string cert;

    connectionString = ConfigurationManager.ConnectionStrings[0].ConnectionString;
    query = "SELECT clientcert FROM settings_services WHERE ID = 1";

    using (SqlConnection cn = new SqlConnection(connectionString))
    {
        SqlCommand cmd = new SqlCommand(query, cn);
        cn.Open();
        cert = (string)cmd.ExecuteScalar();
    }

    X509Certificate2  serverCert = new X509Certificate2(Encoding.UTF8.GetBytes(cert));

This code will correctly load a certificate string (x509 certificate, starting with -----BEGIN CERTIFICATE----- and ending -----END CERTIFICATE-----).

Now I need to get the private key:

My private key is in RSA format (-----BEGIN RSA PRIVATE KEY---- etc...)

I need to load it, and assign it to serverCert, in order to be able to use this certificate for authenticate on web service.

Any suggestions on how to do that?

abatishchev
  • 98,240
  • 88
  • 296
  • 433
  • The answer to this problem you will find it here. http://www.codeproject.com/KB/security/CertificatesToDBandBack.aspx Regards –  Feb 28 '11 at 06:43
  • Related: https://stackoverflow.com/questions/893757 – explunit Apr 07 '15 at 02:11

2 Answers2

9

So this is actually easy, although I found no simple description of it. I've left the cert strings in my gist (sample cert, no secure data)

https://gist.github.com/BillKeenan/5435753

[TestMethod]
public void TestCertificate()
{
    const string publicCert = @"MIIBrzCCARigAwIBAgIQEkeKoXKDFEuzql5XQnkY9zANBgkqhkiG9w0BAQUFADAYMRYwFAYDVQQDEw1DZXJ0QXV0aG9yaXR5MB4XDTEzMDQxOTIwMDAwOFoXDTM5MTIzMTIzNTk1OVowFjEUMBIGA1UEAxMLc2VydmVyMS5jb20wgZ0wDQYJKoZIhvcNAQEBBQADgYsAMIGHAoGBAIEmC1/io4RNMPCpYanPakMYZGboMCrN6kqoIuSI1n0ufzCbwRkpUjJplsvRH9ijIHMKw8UVs0i0Ihn9EnTCxHgM7icB69u9EaikVBtfSGl4qUy5c5TZfbN0P3MmBq4YXo/vXvCDDVklsMFem57COAaVvAhv+oGv5oiqEJMXt+j3AgERMA0GCSqGSIb3DQEBBQUAA4GBAICWZ9/2zkiC1uAend3s2w0pGQSz4RQeh9+WiT4n3HMwBGjDUxAx73fhaKADMZTHuHT6+6Q4agnTnoSaU+Fet1syVVxjLeDHOb0i7o/IDUWoEvYATi8gCtcV20KxsQVLEc5jkkajzUc0eyg050KZaLzV+EkCKBafNoVFHoMCbm3n";
    const string privateCert = @"<RSAKeyValue><Modulus>gSYLX+KjhE0w8Klhqc9qQxhkZugwKs3qSqgi5IjWfS5/MJvBGSlSMmmWy9Ef2KMgcwrDxRWzSLQiGf0SdMLEeAzuJwHr270RqKRUG19IaXipTLlzlNl9s3Q/cyYGrhhej+9e8IMNWSWwwV6bnsI4BpW8CG/6ga/miKoQkxe36Pc=</Modulus><Exponent>EQ==</Exponent><P>mmRPs28vh0mOsnQOder5fsxKsuGhBkz+mApKTNQZkkn7Ak3CWKaFzCI3ZBZUpTJag841LL45uM2NvesFn/T25Q==</P><Q>1iTLW2zHVIYi+A6Pb0UarMaBvOnH0CTP7xMEtLZD5MFYtqG+u45mtFj1w49ez7n5tq8WyOs90Jq1qhnKGJ0mqw==</Q><DP>JFPWhJKhxXq4Kf0wlDdJw3tc3sutauTwnD6oEhPJyBFoPMcAjVRbt4+UkAVBF8+c07gMgv+VHGyZ0lVqvDmjgQ==</DP><DQ>lykIBEzI8F6vRa/sxwOaW9dqo3fYVrCSxuA/jp7Gg1tNrhfR7c3uJPOATc6dR1YZriE9QofvZhLaljBSa7o5aQ==</DQ><InverseQ>KrrKkN4IKqqhrcpZbYIWH4rWoCcnfTI5jxMfUDKUac+UFGNxHCUGLe1x+rwz4HcOA7bKVECyGe6C9xeiN3XKuQ==</InverseQ><D>Fsp6elUr6iu9V6Vrlm/lk16oTmU1rTNllLRCZJCeUlN/22bHuSVo27hHyZ1f+Q26bqeL9Zpq7rZgXvBsqzFt9tBOESrkr+uEHIZwQ1HIDw2ajxwOnlrj+zjn6EKshrMOsEXXbgSAi6SvGifRC2f+TKawt9lZmGElV4QgMYlC56k=</D></RSAKeyValue>";

    var certificate = new X509Certificate2(Convert.FromBase64String(publicCert));

    var crypto = new RSACryptoServiceProvider();

    crypto.FromXmlString(privateCert);

    certificate.PrivateKey = crypto;

    //export a private key
    var exportedPrivate = certificate.PrivateKey.ToXmlString(true);
    var exportedPublic = Convert.ToBase64String(certificate.RawData);

    Assert.AreEqual(publicCert, exportedPublic);
    Assert.AreEqual(privateCert, exportedPrivate);
 }
abatishchev
  • 98,240
  • 88
  • 296
  • 433
Monsters X
  • 2,638
  • 1
  • 19
  • 21
4

You have a constructor with a byte[]. So you can store your certificate as a byte array and load your certificate with

public X509Certificate2(
    byte[] rawData
)

link: http://msdn.microsoft.com/en-us/library/ms148413%28v=VS.100%29.aspx

alexl
  • 6,841
  • 3
  • 24
  • 29
  • This is not applicable to my case. I need to be able let the client generate the private.key and the public cert, then he needs to copy the content of these two files into the DB and save the password for a private key also into the DB. Now, based on these data, from code, I need to create an valid X509Certificate2 object. –  Feb 08 '11 at 13:59
  • @MaiO: This is a detail you should include in your question. At any rate, the stuff between the `-----BEGIN CERTIFICATE-----` and `-----END CERTIFICATE-----` is just Base64 encoded data. A good place to start might be running the text through `Covert.FromBase64String()`. – josh3736 Feb 08 '11 at 15:14
  • 1
    This doesn't actually seem to work, despite what the documentation says. The error is CryptographicException: Cannot find the requested object – r590 Oct 28 '16 at 22:58
  • Be aware that when you use this overload of the constructor, it will write a temporary file to the temp directory. These files don't always get cleaned up and can build up over time. To avoid this, write the data to your own file using File.WriteAllBytes, use the X509Certificate2 constructor that takes a file path to load it, and then afterwards, delete the file in a finally block. – exploring.cheerily.impresses Apr 20 '22 at 19:09