Implementing SmartCardAuthenticationModule

8:51 PM j. montgomery 11 Comments

Page 4 of 9

Previous Page: IIS Configuration | Next Page: SmartCardAuthenticationEventArgs Implementation

Once IIS is configured properly and you have the skeleton of the IHttpModule built, development of the custom IHttpModule can commence.

Here’s an overview of the logic used to authenticate users:

  1. When a user browses the web site, the Smart Card HttpModule will authenticate the Smart Cards against a database of users.
    • If users have a smart card validated by IIS and:
      • They ARE IN the Database; authenticate and authorize them with their roles in the Database (i.e. a small set of users that are Administrators, Moderators, Content Managers, etc.)
      • They ARE NOT IN the Database; we authenticate them in the default ‘Users’ role (i.e. the mass of users who typically have read only access or have limited privileges)
    • If a smart card isn’t authenticated by IIS, give the user a 401.1 access denied page.
  2. Create a strongly typed Smart Card Identity object based on the smart card.
  3. Create a strongly typed Smart Card Principal object and assign it the Identity object.
  4. Attach the Smart Card Principal to the HttpContext, by assigning it to the HttpContext.User property that is available application wide.

SmartCardAuthenticationModule ImplementationSmartCardAuthenticationModule Object

SmartCardAuthenticationModule – Inherits from System.Web.IHttpModule

The SmartCardAuthenticationModule class is the HttpModule that handles the authentication. Its raison de’être is to create an Identity and Principal and attach it to the HttpContext classes User property. Once a principal is attached to the HttpContext object, authorization using that principal will be performed, otherwise if the HttpContext.User property is null, the user is considered unauthenticated and is thus denied by the following authorization setting in the web.config:

1 <authorization>
2 <deny users="?" />
3 </authorization>

An additional feature of the SmartCardAuthenticationModule is the Authenticate Event. This event is automatically wired up by ASP.NET to a method in the Global.asax file called SmartCardAuthentication_Authenticate like so:


C#


1 public class Global : System.Web.HttpApplication
2 {
3 // OPTIONAL CODE TO OVERRIDE DEFAULT SMARTCARD HTTP MODULE BEHAVIOR
4 public void SmartCardAuthentication_Authenticate(
5 object sender,
6 SmartCardAuthenticationEventArgs e)
7 {
8 // Obviously you'd need to load an actual certificate on the next line,
9 // not a byte array with {0,0,0} in it, but an actual X509 certificate
10 X509Certificate customC509Certificate = new X509Certificate(new byte[] { 0, 0, 0 });
11
12 SmartCardIdentity smartCardIdentity = new SmartCardIdentity(customC509Certificate, True);
13 SmartCardPrincipal smartPrincipal = new SmartCardPrincipal(smartCardIdentity);
14
15 // Now set either User property of the HttpContext or the
16 // EventArgs User property
17 e.Context.User = smartPrincipal;
18 // OR;
19 e.User = smartPrincipal;
20 }
21 }

VB.Net

1 Public Class Global
2 Inherits System.Web.HttpApplication
3 ' OPTIONAL CODE TO OVERRIDE DEFAULT SMARTCARD HTTP MODULE BEHAVIOR
4 Sub SmartCardAuthentication_Authenticate(ByVal sender As Object, _
5 ByVal e As SmartCardAuthenticationEventArgs)
6
7 ' Obviously you'd need to load an actual certificate on the next line,
8 ' not a byte array with {0,0,0} in it, but an actual X509 certificate
9 Dim customC509Certificate As New X509Certificate(New Byte() {0, 0, 0})
10
11 Dim smartCardIdentity As New SmartCardIdentity(customC509Certificate, True)
12 Dim smartPrincipal As New SmartCardPrincipal(smartCardIdentity)
13
14 ' Now set either User property of the HttpContext or the
15 ' EventArgs User property
16 e.Context.User = smartPrincipal
17 ' OR
18 e.User = smartPrincipal
19 End Sub
20 End Class

In the Global.asax, custom code can override the default behavior of how the Principal and Identity is resolved and assigned to the HttpContext.User object. You can create and add your own SmartCard Principal/Identity that is resolved perhaps through an already defined database, or another technology. To override the default Principal and Identity objects, code within this method must set either the e.Context.User or the e.User property of the SmartCardAuthenticationEventArgs class.

Next follows the SmartCardAuthenticationModule implementation:
C#


1 using System;
2 using System.Security.Cryptography.X509Certificates;
3 using System.Security.Permissions;
4 using System.Security.Principal;
5 using System.Web;
6
7 namespace SmartCardAuthentication
8 {
9 public delegate void SmartCardAuthenticationEventHandler(object sender,
10 SmartCardAuthenticationEventArgs e);
11
12 public sealed class SmartCardAuthenticationModule :
13 System.Web.IHttpModule
14 {
15 public event SmartCardAuthenticationEventHandler Authenticate;
16
17 public SmartCardAuthenticationModule() { }
18
19 public void Dispose() { }
20
21 public void Init(System.Web.HttpApplication context)
22 {
23 context.AuthenticateRequest +=
24 new EventHandler(new EventHandler(this.OnAuthenticateRequest));
25 }
26
27 private void OnAuthenticateRequest(object source, EventArgs eventArgs)
28 {
29 HttpApplication httpApp = (HttpApplication)source;
30 HttpContext context = httpApp.Context;
31 SmartCardIdentity smartCardIdentity = this.RetrieveIdentity(context);
32
33 this.OnAuthenticate(
34 new SmartCardAuthenticationEventArgs(smartCardIdentity, context)
35 );
36 }
37
38 private void OnAuthenticate(SmartCardAuthenticationEventArgs e)
39 {
40 if (this.Authenticate != null)
41 {
42 // Fire any subscribers to the Authenticate event,
43 // typically from Global.asax Smart
44 this.Authenticate(this, e);
45 }
46
47 // Has Context.User already been assigned
48 // from the Authenticate() event above?
49 if (e.Context.User == null)
50 {
51 // Context.User not populated
52
53 // Did e.User get assigned from
54 // from the Authenticate() event above?
55 if (e.User != null)
56 {
57 // Yes, assign the user and exit.
58 e.Context.User = e.User;
59 }
60 else if (e.Identity != null)
61 {
62 // No, but Identity isn't null from DB Call.
63 // User is authenticated, attach principal to HttpContext
64 e.Context.User = new SmartCardPrincipal(e.Identity);
65 }
66 else
67 {
68 // User isn't authenticated
69 this.Display401Page(e);
70 e.Context.User = null;
71 }
72 }
73 }
74
75 private SmartCardIdentity RetrieveIdentity(HttpContext context)
76 {
77 SmartCardIdentity identity = null;
78 // Validate X509 Certificate
79 if (CryptoUtility.IsHttpCertificateValid(context.Request.ClientCertificate))
80 {
81 // Valid SmartCard, Create the SmartCardIdentity
82 identity = new SmartCardIdentity(context.Request.ClientCertificate);
83 }
84 else
85 {
86 // No Smart Card, or invalid SmartCard
87 // Set the identity to null so they aren't authenticated
88 identity = null;
89 }
90 return identity;
91 }
92
93 private void Display401Page(SmartCardAuthenticationEventArgs e)
94 {
95 string pageName = Configuration.UnauthorizedPage;
96 if (pageName.Equals(string.Empty))
97 {
98 this.WriteErrorPageToResponseStream(e.Context.Response,
99 "<html><body><h1>Unauthorized!</h1></body></html>");
100 }
101 else
102 {
103 this.WriteErroFileToResponseStream(e.Context.Response,
104 Configuration.UnauthorizedPage);
105 }
106 // finally, bypass all further modules in the HTTP pipeline chain
107 // of execution and directly execute the EndRequest event
108 e.Context.ApplicationInstance.CompleteRequest();
109 }
110
111 private void WriteErrorPageToResponseStream(HttpResponse response,
112 string pageContent)
113 {
114 response.StatusCode = 401;
115 response.StatusDescription = "You are not authorized to access this site.";
116 response.ContentType = "text/html";
117 response.Write(pageContent);
118 response.Flush();
119 response.End();
120 }
121
122 private void WriteErroFileToResponseStream(HttpResponse response, string pageName)
123 {
124 response.StatusCode = 401;
125 response.StatusDescription = "You are not authorized to access this site.";
126 response.ContentType = "text/html";
127 response.WriteFile(pageName);
128 response.Flush();
129 response.End();
130 }
131 }
132 }
133

VB.Net


1 Imports System.Security.Cryptography.X509Certificates
2 Imports System.Security.Permissions
3 Imports System.Security.Principal
4 Imports System.Web
5
6 Public NotInheritable Class SmartCardAuthenticationModule
7 Implements System.Web.IHttpModule
8
9 ' Events
10 Public Event Authenticate(ByVal sender As Object, _
11 ByVal e As SmartCardAuthenticationEventArgs)
12
13 Public Sub New()
14 End Sub
15
16 Public Sub Dispose() Implements System.Web.IHttpModule.Dispose
17
18 End Sub
19
20 Public Sub Init(ByVal context As System.Web.HttpApplication) _
21 Implements System.Web.IHttpModule.Init
22
23 AddHandler context.AuthenticateRequest, _
24 New EventHandler(AddressOf Me.OnAuthenticateRequest)
25 End Sub
26
27 Private Sub OnAuthenticateRequest(ByVal source As Object, ByVal eventArgs As EventArgs)
28 Dim httpApp As HttpApplication = DirectCast(source, HttpApplication)
29 Dim context As HttpContext = httpApp.Context
30
31 Dim smartCardIdentity As SmartCardIdentity = Me.RetrieveIdentity(context)
32 Me.OnAuthenticate(New SmartCardAuthenticationEventArgs(smartCardIdentity, context))
33 End Sub
34
35 Private Sub OnAuthenticate(ByVal e As SmartCardAuthenticationEventArgs)
36 ' Fire any subscribers to the Authenticate event,
37 ' typically from Global.asax Smart
38 RaiseEvent Authenticate(Me, e)
39
40 ' Has Context.User already been assigned
41 ' from the Authenticate() event above?
42 If (e.Context.User Is Nothing) Then
43 ' Context.User not populated
44
45 ' Did e.User get assigned from
46 ' from the Authenticate() event above?
47 If (Not e.User Is Nothing) Then
48 ' Yes, assign the user and exit.
49 e.Context.User = e.User
50 ElseIf Not e.Identity Is Nothing Then
51 ' No, but Identity isn't null from Database Call.
52 ' User is authenticated
53 e.Context.User = New SmartCardPrincipal(e.Identity)
54 Else
55 ' User isn't authenticated
56 Me.Display401Page(e)
57 e.Context.User = Nothing
58 End If
59 End If
60 End Sub
61
62 Private Function RetrieveIdentity(ByVal context As HttpContext) As SmartCardIdentity
63 Dim identity As SmartCardIdentity = Nothing
64
65 ' Validate X509 Certificate
66 If CryptoUtility.IsHttpCertificateValid(context.Request.ClientCertificate) Then
67 ' Valid SmartCard, Create the SmartCardIdentity
68 identity = New SmartCardIdentity(context.Request.ClientCertificate)
69 Else
70 ' No Smart Card/Invalid SmartCard
71
72 ' Set the identity to null so they aren't authenticated
73 identity = Nothing
74 End If
75
76 Return identity
77 End Function
78
79 Private Sub Display401Page(ByVal e As SmartCardAuthenticationEventArgs)
80 Dim pageName As String = Configuration.UnauthorizedPage
81 ' Now dump the Unauthorized Page
82 If pageName.Equals(String.Empty) Then
83 Me.WriteErrorPageToResponseStream(e.Context.Response, _
84 "<html><body><h1>Unauthorized!</h1></body></html>")
85 Else
86 Me.WriteErroFileToResponseStream(e.Context.Response, _
87 Configuration.UnauthorizedPage)
88 End If
89
90 ' finally, bypass all further modules in the HTTP pipeline chain of execution
91 ' and directly execute the EndRequest event
92 e.Context.ApplicationInstance.CompleteRequest()
93 End Sub
94
95 Private Sub WriteErrorPageToResponseStream(ByVal response As HttpResponse, _
96 ByVal pageContent As String)
97 response.StatusCode = 401
98 response.StatusDescription = "You are not authorized to access this site."
99 response.ContentType = "text/html"
100 response.Write(pageContent)
101 response.Flush()
102 response.End()
103 End Sub
104
105 Private Sub WriteErroFileToResponseStream(ByVal response As HttpResponse, _
106 ByVal pageName As String)
107 response.StatusCode = 401
108 response.StatusDescription = "You are not authorized to access this site."
109 response.ContentType = "text/html"
110 response.WriteFile(pageName)
111 response.Flush()
112 response.End()
113 End Sub
114 End Class

Previous Page: IIS Configuration | Next Page: SmartCardAuthenticationEventArgs Implementation

Page 4 of 9

11 comments:

  1. hi,

    i read your solution, it looks very good. I'm new user for .net (for C# and .net enviroment) but i just want to know that how client login page will know which smart card reader will used for smart card? I couldn't see any procedure to list exist smart card reader names on client pc. Or .NET uses general procedure for readers (PC/SC readers) to communicate with reader?

    ReplyDelete
  2. Good question. Since this is a web site - we can't directly interact with anything on the client except the web browser (unless we run an ActiveX control which I like to stay away from).

    The Browser will interact with the Operating System to work with the Card Reader - so the task of choosing a card reader would be left up to the desktop configuration in the OS and/or browser.

    ReplyDelete
  3. hi,

    Excellent help and just what I was looking for. I have a simple Q. How do I read/write data from a smartcard on a client PC which is using asp.net page in IE ? It is fairly simple in a .NET application (win32) but I am not clear on how it can be done using aspx.

    Thanks in Advance

    ReplyDelete
  4. ASP.NET doesn't have access to anything on the client. It only has access to what IE provides to the web site - which is strictly the Client Certificate presented by IE to IIS when the user goes to the site.

    The only way to talk directly to the smart card on the client is to run code directly on the client computer - you could use ActiveX (not recommended for security reasons) or embed a .NET control in your web site (just like Active X) that will run on the client computer. You'll have to make sure the .NET Security Policy on each client grants the necessary permissions on the client or else you won't be able to do much.

    ReplyDelete
  5. Hello...

    I searched nearly 2 weeks to develop an ActiveX to communicate with smardcard reader. I want to develop a simple ASP login page (i don't want to use an aspx or .net page because of i don't know to these enviroments).

    So, let's look what i learned :)
    The most simple(i think) way to read certificate,sign data etc from smard card is CAPICOM. Capicom is not used with Vista.

    So i searched capicom. I downloaded a free client certificate from http://www.ascertia.com .Then exported this certificate to my desktop(with private key and strong security). Then i imported this certificate to my GemSafe card with GemSafe ToolBox. So i have a certificate in GemSafe smartcard with protecting PIN.

    So,i want to prepare a login page which use private key of certificate. PIN popup only appears when we want to use private key.

    Now i can sign a text with private key. So users have to enter their PIN because of using private key. So i can compare this signed text on database.

    In fact i want to prepare a ActiveX component which can work with solution on this blog. So i tried to find a way to interaction between response.clientcertificate command and Smartcard.

    I'm confused. And i still couldn't find a way to sign a text with private key with a certificate which is in smartcard. Some guys tell that some middleware programs loads smartcard certificate to "CURRENT_USER_STORE" when we insert smartcard to reader but i don't know whether it's true or not.

    Please show me a way to develop an ASP login page with smartcard.I could only capicom. Is there another way?(with ActiveX or without ActiveX)

    Thanks

    ReplyDelete
  6. Since you are using ASP, you will want to rely on what IIS provides in combination with Internet Explorer. Most of the work will be done for you automatically. No Active X or client side code required. If the user has a smart card reader and client software, that software will typically publish the certificate(s) in their Local User Store in windows. IE then will prompt the user to choose one of these certificates during authentication as long as IIS is allowing/requiring Client Certificates. When the user browses the website, the Smart Card Certificate (Client Certificate) will be presented to the web server and, if accepted, will allow the encrypted connected to be established.

    The questions you need to ask –
    1. Are you mapping users from their Smart Card to a Windows Account?
    2. Are you mapping users from their smart card to a row in the database that represents the user?

    If using method 1 listed above, then you will need to setup user certificate mapping in IIS, if using method two, you will take the USER_CERTIFICATE Form variable which contains the public key portion of the X509 certificate posted by IE. You can then use ASP/VB6 code to parse the X509 certificate, look-up the corresponding user in your DB and authenticate them that way.

    Read more about what IIS gives you with Client Certificates here:
    IIS Configuration for Smart Cards

    All of the IIS principals in the article above will apply with both ASP.NET and ASP (or any other web application you are running on the IIS Web Server).

    ReplyDelete
  7. Thank you very very much for reply. This is the clearest reply i have ever heared. Now i have some simple questions more.

    1-) You told that : "If the user has a smart card reader and client software, that software will typically publish the certificate(s) in their Local User Store in windows"
    What is this client software? You mean that middleware software which comes with smartcard reader or with smartcards?

    2-) I use GemSafe Cards with GemSafe Libraries as middleware software. This middleware software installs a program which name is "Certificate Registiration Tool". I read its pdf and pdf says this :

    "When a smart card is inserted in the reader, the Certificate Registration Tool
    automatically reads the data on the card and attempts to register any certificates for CAPI
    applications that it finds on the card"
    Register means that loading cetificate which is in smartcard to Local User Store? I want to know this because of i have to know which programs must installed client computers of customers. Loading cetificates from smartcard to local user store is a native feature of Microsoft Windows or this is a standart that Software Companies who work with smartcard technology, have to develop their softwares according to this specification?

    3-) How can i use certificate with pin popup? I know that i have to use "Private Key" to get pin popup but as i know private keys never exported from smartcard. May be it's not possible to using with pin prompt...

    4-) I have an idea that i want to share with you(and all users who interest this blog). I just dreamed an OPT (one time password) scenario. As i know we can renew certs with capicom. If i use database to record certificates(your second method),i can renew certificates for each session of users then i can write this certificate to database and also load certificate to smartcard with Capicom ActiveX. First of all users must request a new certificate than they can request login page for authenticating. Then i can match new certificate from database and from their smartcards. What do you think about this utopian idea? :) It's only a dream for me now. I just want to know your ideas about it.

    Again thanks for your replies. I think that a lot of people will learn about this subject and your comments are very clear and understandable.

    ReplyDelete
  8. > 1-) What is this client
    > software? You mean that
    > middleware software which
    > comes with smartcard reader
    > or with smartcards?

    I'm not sure what comes packaged with the SmartCard Reader normally since I'm working in an Enterprise environment.

    I do know that windows XP does have some built in support for smart-cards and a 3rd party client isn't necessarily required, but from what I understand, native Windows XP for Smart Cards is limited and people often need 3rd party software to fill in the gaps.

    Some products I know of are ActivIdentity's ActivClient - this program does make sure the certificates are published in the local certificate store (which can be viewed, by the way, with the Certificate MMC Snap-in), among other things.

    There are also products like TumbleWeed's Desktop Validator which provides additional revocation functions, like OCSP which is missing in Windows XP - It also provides things like IIS Integration for server-side OCSP support, IE, Outlook, Adobe Acrobat, Caching, and more. I am not sure how application support is any different then what Window’s provides.

    > 2-) I use GemSafe Cards with
    > GemSafe Libraries as middleware
    > software. This middleware
    > software installs a program
    > which name is "Certificate
    > Registiration Tool".

    From reading that description from the Docs, I would say yes, it puts the certificate in the Users’ Local Certificate Store. You can double check like this:

    1. Run CertMgr.msc (in Windows\System32 folder).
    2. When prompted, choose, "My User Account"
    3. Expand Certificates -> Personal -> Certificates
    4. If they have been properly added by the Client Software, you should see the smart card user certificates in here.

    > 3-) How can i use certificate
    > with pin popup? I know that i
    > have to use "Private Key" to
    > get pin popup but as i know
    > private keys never exported from
    > smartcard. May be it's not
    > possible to using with pin
    > prompt...

    This should happen automatically – the CAPI provider shows the Pin prompt when an operation happens that requires the use of the private key. So, for example, when you direct IE to use your Client Certificate that is associated with the Smart Card, the pin prompt should pop-up automatically.

    I hope that helps!

    I will follow-up on your next question in an additional comment a bit later.

    ReplyDelete
  9. Hello again.
    i succeed in login process with smartcard on my web page. Everything is good. Thanks for your comment and valuable informations.

    I just have small problems in my mind.

    1-) I verified that gemplus middleware copys certificate to user local store. I checked CertMgr.msc and i verified it.
    Now, i want to do it (copying certificate to user local store when user insert to smartcard to reader) Is there a freeware tool for this purpose?(i will install this tool every clients and GemSafe Libraries can not distributable free of charge). Or may be you have some codes(vb 6.0) for this? May be Capicom can make it. I searched a little bir but i couldn't find anything.

    2-)Is there a way on IIS 6.0 to redirect users who authenticated to any user area page? Or as you told we must parse Request.ClientCertificate("Certificate")
    to identify user? If we have to parse it which object(s) of certificate can we use for the most security? I heared that Request.ClientCertificate("SerialNumber") is good choice for that but i want to hear your idea. In fact i wanted that IIS do it for me but i don't think so.

    3-) I read this from your blog :
    If you include any other Certificate Authorities other then the ones who signed your Smart Card Certificates (like Verisign’s CA’s, or others) any user could purchase a client Certificate from Verisign and present it as a Client Certificate to your web site and you would let them in!!
    I use our server's(Windows 2003) which CA program installed certificate. I wonder that anybody can load or install our certificate without our permission? If can, it's terrible :(

    4-) In read something about Microsot CLM (Certicate Lifecycle Manager). What do you think about this service?

    Thanks and have a nice day.

    ReplyDelete
  10. 1) You'll have to figure out how to connect and read data from the Smart Card directly - I've never had to do this since the driver always handles this scenario, here's some info I've found in the MSDN forum:

    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=447924&SiteID=1

    http://www.codeproject.com/smartclient/smartcardapi.asp

    Perhaps these can help?

    2) You'll have to handle the redirect in the ASP code. ASP.NET makes this a bit easier to implement then classic ASP, IMO. You'll need to make sure you validate users on every page you want to secure. I store a SHA1 hash of the Public key in the database. The when the user presents their smart card to IIS, I look-up the user in the database for authentication by regenerating a hash of the Public Key from the USER_CERTIFICATE.

    I can't recall how the serial number is generated, but if happens to be modifiable and if someone has a valid smart card and are able to change the serial number without changing the Certificate, they could potentially impersonate another user (there's a lot of "if's" in this scenario). I know that the Kinkos smart cards were vulnerable to this sort of attack because they didn't secure the serial number properly (could be a different serial number then the one in the certificate) - again, I'm not sure of all the details. The main thing is to throughly research how you're going to handle the authentication so that there are no ways to bypass it without invalidating the user certificate, which will in turn, invalidate the IIS validation of the smart card.

    3) Microsoft includes, for free, a bunch of 3rd party Certificate authorities. You'll need to make sure you setup IIS to only allow specific Trusted Root CAs and not all of them. The other option is to delete them, but be very careful - some of the trusted roots are required for Windows to function.

    4) CLM looks interesting, but it's still in Beta and I haven't had a chance to really look it over. An important, overdue addition includes OCSP support (amoung other items), so that's promising.

    ReplyDelete
  11. J,

    Hello! What a cool article. I work for a local identity management ISV in Columbus. I wanted to see if you would be available for a chat about a possible project we have in the works?

    Thanks!

    Patrick
    patrick@thedotnetfactory.com

    ReplyDelete