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

R

romiko2000

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
expected.

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 =
X509Certificate.CreateFromCertFile("d:\ClientCert\TachoClient.cer")
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 HTTPS SUPPORT
'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
System.Net.ICertificatePolicy.CheckValidationResult

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
InitializeComponent()

End Sub
Protected WithEvents dgResults As
System.Web.UI.WebControls.DataGrid
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.
InitializeComponent()
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")
dt.Columns.Add(dc)

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

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

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

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

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

If Not IsPostBack Then 'IMPORTANT Do not rebuild Data Grid, so
execute once
'Populate the Datagrid
dgResults.DataSource = dt
dgResults.DataBind()
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""?>" & _
"<MS2TCN_CheckIssuedCards_Req
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>" & _
"</MS2TCN_CheckIssuedCards_Req>"

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



'2 way ssl setup
Dim cert As X509Certificate =
X509Certificate.CreateFromCertFile("d:\ClientCert\TachoClient.cer")
Response.Write("Client Certificate Sent" & cert.GetName() &
"<br>")

Try
System.Net.ServicePointManager.CertificatePolicy = New
TrustedCertificatePolicy
time = Date.Now 'Get the time which will be used by
exceptions
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.ClientCertificates.Add(cert)
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
Type
'Open Stream
xmlWriter = New XmlTextWriter(wReq.GetRequestStream(),
System.Text.Encoding.UTF8)
'Send the XML Data
xmlDoc.WriteTo(xmlWriter)
xmlWriter.Close()

'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"
Else
dr("Status") = "Down"
End If
End If
wResp.Close()

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



If Not CType(wex.Response, Net.HttpWebResponse) Is Nothing
Then
dr("HTTP Code") = CType(wex.Response,
Net.HttpWebResponse).StatusCode
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"
Finally
interval = Date.Now.Subtract(time).TotalSeconds
dr("Seconds") = interval.ToString("f3")
If Not xmlWriter Is Nothing Then
xmlWriter.Close()
End If
If Not wResp Is Nothing Then
wResp.Close()
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
Reference
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
Else
lblError.Visible = False
End If

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

dgResults.DataSource = dt
dgResults.DataBind()
End Sub

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

'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
Else
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
dgResults.SelectedIndexChanged

End Sub
End Class
 
R

romiko2000

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

http://support.microsoft.com/?id=817854



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
(http://www.microsoft.com/downloads/...61-4a92-4106-a9bc-83e78d4abc5b&displaylang=en)
or .NET Framework 1.1 Service Pack 1
(http://www.microsoft.com/downloads/...4f-088e-40b2-bbdb-a83353618b38&displaylang=en)
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



http://www.microsoft.com/downloads/...ac-3409-40e9-8667-c748e422833f&displaylang=en




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
Store.

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
BrazilianFrenchGermanItalianJapaneseKoreanRussianSimplified
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
SYMPTOMS
CAUSE
RESOLUTION
WORKAROUND
STATUS
MORE INFORMATION
APPLIES TO

SYMPTOMS
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

CAUSE
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

RESOLUTION
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:
http://support.microsoft.com/default.aspx?scid=fh;[LN];CNTACTMS
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
System.runtime.remoting.dll
02-Apr-2003 05:56 1.0.3705.418 503,808 System.web.services.dll
Back to the top

WORKAROUND
For information about how to work around this problem without applying
the hotfix, visit the following Microsoft Web site:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/secnetht13.asp
Back to the top

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

MORE INFORMATION
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
store.

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:
http://msdn.microsoft.com/library/e...cfg_exe__a_certificate_configuration_tool.asp
To obtain the WinHttpCertCfg utility, visit the following Microsoft Web
site:
http://www.microsoft.com/downloads/...ac-3409-40e9-8667-c748e422833f&displaylang=en
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);
req.SetClientCertificate("LOCAL_MACHINE\\Root\\YourCert");
//path of the certificate and the certificate name (for example,
Path\certname)
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
Base:
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


--------------------------------------------------------------------------------

APPLIES TO
· 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?
Yes
No
Maybe
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
(optional):





Thank you for your comments.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top