2-way ssl and asp.net wReq.ClientCertificates.Add()

Discussion in 'ASP .Net Security' started by romiko2000@yahoo.co.uk, Apr 15, 2005.

  1. Guest

    Hi All!

    I am busy developing the probe tool to ensure that end to end
    communication is working, this is done by sending an xml message to a
    server, and they accept it.

    I have now included SSL support, currently, I have created a Certficate
    policy to accept any server certificate, I will later add the code with
    a custom requirment to verify if the server certificate is fine, hence
    the Return true in the code.

    I have a problem with 2-way ssl, as you can see in the code, I am able
    to send a client certificate out, however, it is not working as

    I then created an impersonate user, for the asp.net application to run
    under, and installed the client certificate (with private key) into the
    impersonate user's certificate store.

    As I understand it, the
    Dim cert As X509Certificate =
    Will load the DER version of the certificate, then check for the
    corresponding private key in the certificate store.

    I installed this in the local computer certificate store, the asp.net
    service store and also the impersonate user (declared in the
    web.config), and still the client certificate is not being sent
    correctly, I tested this by creating a custom virtual directoy
    requiring a client certificate, and it was rejected.

    The problem is the web server is not accepting the client certificate,
    the virtual directory is configured correctly.

    There is not allot of documentation of the
    wReq.ClientCertificates.Add() method, and configuring access to client
    certificates from .NET apps.

    Below is the complete code. As I mentioned, the certificate policy
    class overides the default policy to accept all server certificates, I
    did this temporary, so I can isolate the client certificate problem,
    also, I can verify that the client certificate is instantiated
    correctly, since the following line of code, shows the common name of
    the cert once loaded.

    Response.Write("Client Certificate Sent" & cert.GetName() & "<br>")

    Here is the full program, without the aspx data.

    'Author: Romiko Derbynew
    'Date: 2004-12-21
    'Version: 0.1
    'Purpose: Check if Memberstates XML Services are running and are able
    to accept XML messages
    'TODO ADD Time to show Millesconds response

    Imports System.Net
    Imports System.Xml
    Imports MetaBuilders.WebControls
    Imports System.Security
    Imports System.Security.Cryptography.X509Certificates

    'overide the default ssl policy
    Public Class TrustedCertificatePolicy
    Implements ICertificatePolicy

    Public TrustedCertificatePolicy()

    Public Function CheckValidationResult(ByVal srvPoint As
    System.Net.ServicePoint, ByVal certificate As
    System.Security.Cryptography.X509Certificates.X509Certificate, ByVal
    request As System.Net.WebRequest, ByVal certificateProblem As Integer)
    As Boolean Implements

    Return True
    End Function
    End Class

    Public Class Monitor
    Inherits System.Web.UI.Page

    #Region " Web Form Designer Generated Code "

    'This call is required by the Web Form Designer.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub

    End Sub
    Protected WithEvents dgResults As
    Protected WithEvents btnCancel As System.Web.UI.WebControls.Button
    Protected WithEvents btnStart As System.Web.UI.WebControls.Button
    Protected WithEvents btnMonitor As System.Web.UI.WebControls.Button

    Protected WithEvents Image1 As System.Web.UI.WebControls.Image
    Protected WithEvents Image2 As System.Web.UI.WebControls.Image
    Protected WithEvents lblError As System.Web.UI.WebControls.Label
    Protected WithEvents lblNote As System.Web.UI.WebControls.Label
    Protected WithEvents Literal1 As System.Web.UI.WebControls.Literal

    'NOTE: The following placeholder declaration is required by the Web
    Form Designer.
    'Do not delete or move it.
    Private designerPlaceholderDeclaration As System.Object

    Private Sub Page_Init(ByVal sender As System.Object, ByVal e As
    System.EventArgs) Handles MyBase.Init
    'CODEGEN: This method call is required by the Web Form Designer

    'Do not modify it using the code editor.
    End Sub

    #End Region

    'Initialise variable for the Web.Config File
    Private configApp As System.Configuration.ConfigurationSettings
    'Data Set and Table Variables
    Private dt As DataTable
    Private dv As DataView

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As
    System.EventArgs) Handles MyBase.Load

    Dim strKey As String 'Store the Key from <AppSettings>
    Dim strCountry As String

    'Setup Data Table
    Dim dc As DataColumn
    Dim dr As DataRow
    dt = New DataTable

    dc = New DataColumn
    dc.ColumnName = "Country"
    dc.DataType = System.Type.GetType("System.String")

    dc = New DataColumn
    dc.ColumnName = "HTTP Code"
    dc.DataType = System.Type.GetType("System.String")

    #If CONFIG <> "MemberStateUse" Then
    dc = New DataColumn
    dc.ColumnName = "Error"
    dc.DataType = System.Type.GetType("System.String")
    #End If

    dc = New DataColumn
    dc.ColumnName = "Status"
    dc.DataType = System.Type.GetType("System.String")

    dc = New DataColumn
    dc.ColumnName = "Seconds"
    dc.DataType = System.Type.GetType("System.String")

    ' For each URL in AppSettings, assign the URL value
    For Each strKey In configApp.AppSettings.Keys()
    dr = dt.NewRow
    dr("Country") = strKey

    If Not IsPostBack Then 'IMPORTANT Do not rebuild Data Grid, so
    execute once
    'Populate the Datagrid
    dgResults.DataSource = dt
    lblNote.Visible = True
    End If
    End Sub
    Private Function GenerateXMLMessage(ByVal dr As DataRow)
    'Setup Variables
    Dim time As DateTime
    Dim interval As Double
    Dim timer1 As Long
    Dim timer2 As Long
    Dim milliseconds As Long
    Dim xmlDoc As New XmlDocument
    Dim wReq As HttpWebRequest
    Dim wResp As WebResponse
    Dim xmlWriter As XmlTextWriter
    Dim STRxml As String = "<?xml version=""1.0""
    encoding=""UTF-8""?>" & _
    xmlns=""urn:eu.cec.tren.tcn"" > " & _
    "<Header Version=""1.4""
    SentAt=""2004-04-01T00:00:00"" From=""TCN"" To=""TCN""
    MSRefId=""Monitor"" TimeoutValue=""60""></Header>" & _

    " <Body> " & _
    "<SearchedDriver Surname=""Monitor""
    FirstName=""Montior"" BirthDate=""1900-01-01""></SearchedDriver>" & _

    "</Body>" & _

    '1 way ssl setup
    'Override the default Certificate policy to accept the server

    '2 way ssl setup
    Dim cert As X509Certificate =
    Response.Write("Client Certificate Sent" & cert.GetName() &

    System.Net.ServicePointManager.CertificatePolicy = New
    time = Date.Now 'Get the time which will be used by
    xmlDoc.LoadXml(STRxml) 'Load Test Data
    wReq =
    HttpWebRequest.Create(configApp.AppSettings(dr("Country"))) ' Connect
    to URL using the Country as key in Data Table

    wReq.Timeout = 30000
    lblNote.Text = "The Default Timeout is set to: " &
    CType((wReq.Timeout / 1000), String) & " Seconds"
    wReq.Method = "POST" 'Set HTTP Method
    wReq.ContentType = "text/xml charset=utf-8" ' Set Content
    'Open Stream
    xmlWriter = New XmlTextWriter(wReq.GetRequestStream(),
    'Send the XML Data

    'Get Response Stream
    time = Date.Now 'If an exception did not occur, grab the
    time here
    wResp = wReq.GetResponse
    If TypeOf wResp Is HttpWebResponse Then
    dr("HTTP Code") = CType(wResp,
    HttpWebResponse).StatusCode 'Convert to HTTPWebResponse
    If CType(wResp, Net.HttpWebResponse).StatusCode =
    HttpStatusCode.Accepted Or _
    CType(wResp, Net.HttpWebResponse).StatusCode =
    HttpStatusCode.OK Then
    dr("Status") = "UP"
    dr("Status") = "Down"
    End If
    End If

    'Catch HTTP Execeptions
    Catch wex As WebException
    Response.Write(wex.Message & "<br>")

    If Not CType(wex.Response, Net.HttpWebResponse) Is Nothing
    dr("HTTP Code") = CType(wex.Response,
    End If
    dr("Status") = "Down"
    dr("HTTP Code") = "N/A"
    Catch ex As Exception
    #If CONFIG <> "MemberStateUse" Then
    dr("Error") = ex.Message & " " & ex.StackTrace
    #End If

    dr("Status") = "Down"
    dr("HTTP Code") = "N/A"
    interval = Date.Now.Subtract(time).TotalSeconds
    dr("Seconds") = interval.ToString("f3")
    If Not xmlWriter Is Nothing Then
    End If
    If Not wResp Is Nothing Then
    End If
    End Try

    End Function

    Private Sub btnMonitor_Click(ByVal sender As System.Object, ByVal e
    As System.EventArgs) Handles btnStart.Click, btnMonitor.Click

    Dim rsc As RowSelectorColumn =
    RowSelectorColumn.FindColumn(dgResults) 'RowSelector Check Box
    Dim selectedIndex As Integer

    If rsc.SelectedIndexes.Length = 0 Then
    lblError.Visible = True
    lblError.Text = "Please select the Countries you would like
    to monitor"
    lblError.ForeColor = Drawing.Color.Red
    Exit Sub
    lblError.Visible = False
    End If

    For Each selectedIndex In rsc.SelectedIndexes
    GenerateXMLMessage(dt.Rows(selectedIndex)) 'Only send the
    Data Rows selected

    dgResults.DataSource = dt
    End Sub

    Private Sub dgResults_ItemDataBound(ByVal sender As Object, ByVal e
    As System.Web.UI.WebControls.DataGridItemEventArgs) Handles

    'Dim control As System.Web.UI.Control
    If e.Item.ItemType = ListItemType.AlternatingItem Or
    e.Item.ItemType = ListItemType.Item Then
    If e.Item.Cells(2).Text = "OK" Or e.Item.Cells(2).Text =
    "Accepted" Then
    e.Item.Cells(2).ForeColor = System.Drawing.Color.Green
    e.Item.Cells(4).ForeColor = System.Drawing.Color.Green
    e.Item.Cells(2).ForeColor = System.Drawing.Color.Red
    e.Item.Cells(4).ForeColor = System.Drawing.Color.Red
    End If
    End If
    End Sub

    Private Sub dgResults_SelectedIndexChanged(ByVal sender As
    System.Object, ByVal e As System.EventArgs) Handles

    End Sub
    End Class
    , Apr 15, 2005
    1. Advertisements

  2. Guest

    Hi again,

    I have solved the problem with the httpwebrequest problem.

    It is most likely that you are being affected by the problem described
    in the following article:

    FIX: ASP.NET Web Application Cannot Deliver a Client Certificate to a
    Secure Web Site


    In order to make sure we are actually facing the problem described in
    the article above, I need you to follow the steps below and check if
    the application works correctly in this case:

    1) Install .NET Framework 1.0 Service Pack 3
    or .NET Framework 1.1 Service Pack 1
    depending on what version of .NET Framework you have installed in the
    client machine (the one making the httpwebrequest)

    2) Download the winhttpcertcfg.exe utility from


    3) Open the Certificates console with the steps below:

    a. Start\Run, mmc.exe

    b. Add\remove snapin, select certificates, add Current User.

    c. Add\remove snapin, select certificates, add Local Computer

    d. Select under the personal store the certificate that you are
    using (the corresponding to TachoClient.cer), and right-click, select
    All Tasks\Export. Select "Yes, export the private key"

    e. Leave the default options for the rest, and save the pfx file
    to any folder.

    4) From command-line, from the tool installation directory, run the
    following (modify c:\folderselected\TachoClient.pfx with the
    corresponding path):

    winhttpcertcfg -i c:\folderselected\TachoClient.pfx -c LOCAL_MACHINE\My
    -a ASPNET

    With the command above, we are installing the certificate with the
    private key in local machine store and we are giving ASPNET user,
    permissions to access the store.

    5) Check that under Current User\Trusted Root Certification
    Authorities, you have Belgacom E-Trust Primary CA certificate, and
    under under Current User \Intermediate Certification Authorities, you
    have Certipost E_Trust Primary CA certificate

    6) Copy (right click) Current User\Trusted Root Certification
    Authorities\Belgacom certificate and paste it to Local Computer\Trusted
    Root Certification Authorities.

    7) Copy (right click) Current User\ Intermediate Certification
    Authorities\Certipost certificate and paste it to Local Computer\
    Intermediate Certification Authorities

    8) Restart IIS services using iisreset in client machine

    9) Test your application again. Is it still failing? What is the
    exception being generated?

    No other place on the internet has this solution, this is the best way
    to do it.

    DO NOT overide the default cert policy like I did in the code, I am
    going to change it to be highyl secure, else 1-way ssl will be unsecure
    and only 2-way will be, good luck.

    Microsoft.com Home

    Search Microsoft.com for:

    Help and Support Home | Select a Product | Search (Knowledge Base) |
    Contact Microsoft

    Article Translations
    ChineseSpanishTraditional Chinese

    Related Support Centers
    · Microsoft .NET Framework

    Other Support Options
    · Contact Microsoft
    Phone Numbers, Support Options and Pricing, Online Help, and more.

    · Customer Service
    For non-technical assistance with product purchases, subscriptions,
    online services, events, training courses, corporate sales, piracy
    issues, and more.

    · Newsgroups
    Pose a question to other users. Discussion groups and Forums about
    specific Microsoft products, technologies, and services.

    Page Tools
    Print this page

    E-mail this page

    Microsoft Worldwide

    Save to My Support Favorites

    Go to My Support Favorites

    Send Feedback

    FIX: ASP.NET Web application cannot deliver a client certificate to a
    security-enhanced Web site
    View products that this article applies to.
    Article ID : 817854
    Last Review : January 7, 2005
    Revision : 4.1
    On this page

    You try to call a Web service or another HTTP resource or HTTPS
    resource, and the Web service or the resource is security-enhanced by
    using a client certificate. If the client certificate is implemented by
    using the Microsoft .NET Framework, your code may work when you run it
    in a Microsoft Windows Forms application or in a console application.
    However, the same code does not work when you run it in the context of
    Microsoft ASP.NET.

    For example, when you run the code in an ASP.NET Web application, you
    receive the following error message:
    System.Net.WebException. The Underlying Connection Was Closed. Could
    Not Establish Trust Relationship with Remote Server.
    Back to the top

    This problem occurs because the System.Net classes look only in the
    certificate store of the current user. However, code that is running in
    the context of a non-interactive account, such as the ASPNET account or
    the Network Service account that ASP.NET uses, cannot access this
    certificate store.
    Back to the top

    Apply the following hotfix. After you apply this hotfix, the System.Net
    classes will also look in the certificate store of the local computer.
    If the certificate is installed, and the correct permissions have been
    granted in the certificate store of the local computer, the code will
    work as expected.

    A supported hotfix is now available from Microsoft, but it is only
    intended to correct the problem that is described in this article. Only
    apply it to systems that are experiencing this specific problem. This
    hotfix may receive additional testing. Therefore, if you are not
    severely affected by this problem, we recommend that you wait for the
    next .NET Framework 1.0 service pack that contains this hotfix.

    To resolve this problem immediately, contact Microsoft Product Support
    Services to obtain the hotfix. For a complete list of Microsoft Product
    Support Services phone numbers and information about support costs,
    visit the following Microsoft Web site:
    Note In special cases, charges that are ordinarily incurred for support
    calls may be canceled if a Microsoft Support Professional determines
    that a specific update will resolve your problem. The usual support
    costs will apply to additional support questions and issues that do not
    qualify for the specific update in question.

    The English version of this hotfix has the file attributes (or later
    file attributes) that are listed in the following table. The dates and
    times for these files are listed in coordinated universal time (UTC).
    When you view the file information, it is converted to local time. To
    find the difference between UTC and local time, use the Time Zone tab
    in the Date and Time tool in Control Panel. Date Time
    Version Size File name

    02-Apr-2003 05:52 1.0.3705.418 20,480 Perfcounter.dll
    02-Apr-2003 06:01 1.0.3705.418 1,175,552 System.dll
    02-Apr-2003 05:04 1.0.3705.418 311,296
    02-Apr-2003 05:56 1.0.3705.418 503,808 System.web.services.dll
    Back to the top

    For information about how to work around this problem without applying
    the hotfix, visit the following Microsoft Web site:
    Back to the top

    Microsoft has confirmed that this is a bug in the Microsoft products
    that are listed in the "Applies to" section.
    Back to the top

    After this fix is installed, the client certificate must be installed
    in the Machine store. Use the MMC Certificate snap-in to add the
    certificate in the following location:
    Certificates (Local Computer)\Personal\Certificates

    Warning You can use the MMC Certificate snap-in to import the
    certificate directly to the Certificates (Local Computer) store.
    However, if you have already imported the certificate to the current
    user's store, do not use the drag-and-drop method in the MMC
    Certificate snap-in to move the certificate to the Local Computer

    For example, earlier, you double-clicked the certificate (.cer) file
    and then followed the instructions in the wizard to import the
    certificate to the current user's store. If you now use the
    drag-and-drop method in the MMC Certificate snap-in to move the
    certificate to the Local Computer store, the private key is not copied
    during the move operation. The private key is required to complete the
    certificate authentication handshake with the server.

    For additional information about this problem, click the following
    article number to view the article in the Microsoft Knowledge Base:
    837350 ISA Server 2000 cannot access an imported SSL certificate
    The WinHttpCertCfg utility can be used to put a certificate in the
    correct store and to add permissions for the ASP.NET user to access the
    certificate. For more information about the WinHttpCertCfg utility,
    visit the following Microsoft Developer Network (MSDN) Web site:
    To obtain the WinHttpCertCfg utility, visit the following Microsoft Web
    After the certificate is in the certificate store, and after the
    correct user has been added and has been granted the correct
    permissions, you can use the following code to send the certificate as
    part of the request: WinHttp.WinHttpRequest
    req = new WinHttp.WinHttpRequestClass();
    req.Open("GET", <<Https://YourURL>> , false);
    //path of the certificate and the certificate name (for example,
    For example, for the ASP.NET user, the ASPNET user account must be
    added and must be granted the correct permissions.

    Note This issue is also fixed in the .NET Framework 1.1 through the
    June 2003 ASP.NET hotfix package. For additional information, click the
    following article number to view the article in the Microsoft Knowledge
    821156 ASP.NET 1.1 June 2003 hotfix rollup package
    Note You cannot obtain the 1.1 version of this hotfix individually. You
    must install the rollup.
    Back to the top


    · Microsoft .NET Framework 1.0

    Back to the top

    Keywords: kbmsccsearch kbpubtypekc kbqfe kbnetframe100presp3fix kbfix
    kbbug KB817854

    Back to the top

    Did this content help you?
    Please select one option based on your first choice:
    I'm very satisfied
    I think it will help, but I haven't tried it yet
    It is helpful, but I need more information
    It is helpful, but hard to understand
    Seemed relevant in search results, but didn't help me
    The information is wrong
    The page contains one or more broken links
    Suggest new content or let us know how we can improve this content

    Thank you for your comments.
    , Apr 26, 2005
    1. Advertisements

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jens Mehl
    Jens Mehl
    Aug 21, 2003
  2. Chandy


    Chandy, Feb 18, 2004, in forum: ASP .Net
    Feb 18, 2004
  3. ECS
  4. John Smith
    John Smith
    Oct 5, 2006
  5. Replies:
  6. Robson Carvalho Machado

    CAPICOM and ClientCertificates

    Robson Carvalho Machado, Apr 26, 2006, in forum: ASP .Net Security
    Robson Carvalho Machado
    Apr 27, 2006
  7. Nathan Crosby

    ASP.net SSL w/ an SSL Accelerator

    Nathan Crosby, Jul 25, 2006, in forum: ASP .Net Security
    Nathan Crosby
    Aug 18, 2006
  8. Pavel Smerk
    Michal Suchanek
    Aug 15, 2006