locked
Choose a certificate dialog box

    Question

  • Hi,

    Iam having difficulties to talk to a server application over HTTPs using C# client. When I try the url using browser i get "choose a certificate" dialog box. I suspected for this reason it is not working through my application. I disabled this option from IE now IE is not prompting for a certificate. How can i handle this from my application.

    Thanks,

    Rabia

    Monday, March 05, 2007 2:32 PM

Answers

  • If your server requires a client sertificate you can browse through the certificates in you local machine store or in your user account (your choice), pick one according to your criteria and send it.

    Or you can export the client certificate you want to use to a file, put it in the same directory from which your app is running and then do something like this

    static void DoWebRequest()
    {
    string fullUriString;
    string host = "your host name";
    string path = "your path here...";
    int port = 443;

    //this is to validate your server certificate. To keep it simple I am not doing any validation, but you should.
    ServicePointManager.ServerCertificateValidationCallback =
    new RemoteCertificateValidationCallback(ValidateServerCertificate);
    scheme =
    "https";

    fullUriString = "https://" + host + ":" + port.ToString() + path;
    Console.WriteLine("the full uri is: " + fullUriString);
    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(fullUriString);

    req.ClientCertificates.Add(X509Certificate.CreateFromCertFile("yourcertificatename.cer"));
    req.Credentials = CredentialCache.DefaultCredentials;
    HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
    Stream s = resp.GetResponseStream();
    StreamReader sr = new StreamReader(s, Encoding.UTF8);
    Console.WriteLine(sr.ReadToEnd());
    sr.Close();
    s.Close();
    }

    public static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
    return true;
    }

     

    Now if you want to browse through the certificates (lets say in the Local Machine Store), and choose the one issued to your machien then do the following

    Console.WriteLine("Opening System Store to read all Server certs");
    X509Store store = new X509Store(StoreLocation.LocalMachine);
    store.Open(OpenFlags.ReadOnly);

    //Assumption is we have certs. If not then this call will fail
    try
    {
    foreach (X509Certificate2 cert in store.Certificates)
    {

    if (cert.Subject.ToUpper().IndexOf(Environment.MachineName.ToUpper()) >= 0) 
    {
    return cert;
    }

    catch (Exception e)
    {
    Console.WriteLine(e.ToString());
    }
    finally
    {
    if (store != null) store.Close();
    }

    }

     

    Hope this helps
    Mariya

    Monday, March 05, 2007 7:03 PM

All replies

  • If your server requires a client sertificate you can browse through the certificates in you local machine store or in your user account (your choice), pick one according to your criteria and send it.

    Or you can export the client certificate you want to use to a file, put it in the same directory from which your app is running and then do something like this

    static void DoWebRequest()
    {
    string fullUriString;
    string host = "your host name";
    string path = "your path here...";
    int port = 443;

    //this is to validate your server certificate. To keep it simple I am not doing any validation, but you should.
    ServicePointManager.ServerCertificateValidationCallback =
    new RemoteCertificateValidationCallback(ValidateServerCertificate);
    scheme =
    "https";

    fullUriString = "https://" + host + ":" + port.ToString() + path;
    Console.WriteLine("the full uri is: " + fullUriString);
    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(fullUriString);

    req.ClientCertificates.Add(X509Certificate.CreateFromCertFile("yourcertificatename.cer"));
    req.Credentials = CredentialCache.DefaultCredentials;
    HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
    Stream s = resp.GetResponseStream();
    StreamReader sr = new StreamReader(s, Encoding.UTF8);
    Console.WriteLine(sr.ReadToEnd());
    sr.Close();
    s.Close();
    }

    public static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
    return true;
    }

     

    Now if you want to browse through the certificates (lets say in the Local Machine Store), and choose the one issued to your machien then do the following

    Console.WriteLine("Opening System Store to read all Server certs");
    X509Store store = new X509Store(StoreLocation.LocalMachine);
    store.Open(OpenFlags.ReadOnly);

    //Assumption is we have certs. If not then this call will fail
    try
    {
    foreach (X509Certificate2 cert in store.Certificates)
    {

    if (cert.Subject.ToUpper().IndexOf(Environment.MachineName.ToUpper()) >= 0) 
    {
    return cert;
    }

    catch (Exception e)
    {
    Console.WriteLine(e.ToString());
    }
    finally
    {
    if (store != null) store.Close();
    }

    }

     

    Hope this helps
    Mariya

    Monday, March 05, 2007 7:03 PM
  • Hi,

    Thanks for you reply.

    My senario goes like this:

    I have a C# client developed using VS 2003. This talks to a java server application over Https using XML messages. I have been issued a certificate from a server application and I issued them a certificate as well.

    Every thing works fine (both from the browser and my application) when I use their certificate and they don't use my certificate. When they start using my certificate and I try a request from the browser following happens:

    Browser prompts me to choose a certificate to be used for authenticating the server. When i select the certificate I get a message box saying IE is trying to access the private key. When i press ok every thing works fine.

    When I try the same from my application I get an Exception:

    "Unable to establish secure communication using SSL" . "An error occured while processing the certificate"

    Can you help me out with this.

    Thanks,

    Rabia.

    Monday, March 05, 2007 9:14 PM
  • VS 2003 contains an older version of the framework - beta 1 if I remember correctly. It is very possible that this problem has already been corrected in the final release. You can download it for free from the web and try, but I have to warn you not to install it on the same machine on which you have VS 2003 because the 2 framework versions will contradict.

    Try the following - extract the certificate without exporting the private key (.cer), save it to a folder and then try accessing it from there. You can do this either through IE -> export certificate or through mmc

    Mariya

    Tuesday, March 06, 2007 3:10 AM
  • Thanks Mariya,

    Is there any way that I can use "LocalCertificateSelectionCallback" with the HTTP web request or is there any other thing that is equivalent to this.

    Regards,

    Rabia

     

    Thursday, March 08, 2007 1:35 PM
  • Thanks Mariya,

    Is there any way that I can use "LocalCertificateSelectionCallback" with HttpWebRequest. Or is there any equivalent of this.

    Regards,

    Hashim Ahmed

    Thursday, March 08, 2007 1:48 PM
  • Yes and no. You can call this callback the way you'd call any other callback. And no, it won't work the same way as the  RemoteCertificateValidationCallback with the ServicePointManager. Anyway, it all boils down to the same thing: what that callback does is go to the certificate store and choose a certificate by issuer

    Here is the text from the sample for LocalCertificateSelectionCallback

            // Use the first certificate that is from an acceptable issuer.
            foreach (X509Certificate certificate in localCertificates)
            {
                string issuer = certificate.Issuer;
                if (Array.IndexOf(acceptableIssuers, issuer) != -1)
                    return certificate;
            }
            // Use the first certificate that is from an acceptable issuer.
            foreach (X509Certificate certificate in localCertificates)
            {
                string issuer = certificate.Issuer;
                if (Array.IndexOf(acceptableIssuers, issuer) != -1)
                    return certificate;
            }

    It is up to you how you structure your code.

    Mariya

    Thursday, March 08, 2007 10:43 PM
  • Thanks Again Maria,

    I might sound a bit childish but i have never used to callback in C# before. Can you give me an example how can i assign my custom function to "LocalCertificateSelectionCallback" delegate. And will this function invoke automayically when I use HTTPWebrequest.

    Thanks,

    Rabia

    Saturday, March 10, 2007 8:00 AM
  • There is an example in the docs on how to use the callback
    http://msdn2.microsoft.com/en-us/library/system.net.security.localcertificateselectioncallback.aspx
    For more info on callbacks you can google for "using callbacks in C#" :-)

    This callback won't be invoked automatically when you use HttpWebRequest.

    You're not required to use this particualr callback - all it does is loop through the certificates in your store and choose one according to a certain criteria. I've already given you the code on how to do this.

    Mariya

    Tuesday, March 13, 2007 7:26 PM