Archive

Archive for the ‘eID’ Category

Authenticating users with the Belgium eID in ASP.NET

August 14, 2015 10 comments

Every Belgium resident has an eID card. This card functions as PKCS#11 keystore containing two X509 certificates (including their private keys): one for authentication and one for digital signing. These certificates are protected against a PIN/PUK code. The card can be used to authenticate the user in a web application using HTTPS with client certificate authentication. Because this mode of authentication makes use of two out of the three different types of information that can be used for authentication (something you know and something you have), it can be considered strong authentication.

In a classic HTTPS scenario, only the server will prove its identity to the user by making use of its X509 certificate, it is then up to the web application to do an authentication of the user in applicative code (over the secure SSL tunnel). With client certificate authentication, both the server and the user (in fact the browser) will prove their identity by making use of their X509 certificate.

eID authentication in ASP.NET

Authentication based on the Belgium eID card can be easily integrated into an ASP.NET web application. I have created the necessary code as an OWIN middleware component that can hooked into your web application and that will create a ClaimsIdentity representing the user. You can already find the source at Github (https://github.com/pieterderycke/Eid.Owin), but in the comming days I will also create a NuGet package for it.

The first thing you must do, is configure your web application to allow or require client certificates in IIS.

2015-08-04 19_54_32-Internet Information Services (IIS) Manager

2015-08-04 19_57_36-Internet Information Services (IIS) Manager

Once this is done, we can read out the client certificate in our OWIN middleware. There are a number of properties that can be parsed from the certificate. My code will create claims for all these properties

public class EidAuthenticationHandler : AuthenticationHandler
{
    protected override async Task AuthenticateCoreAsync()
    {
        var x509 = Context.Get("ssl.ClientCertificate");

        if (x509 != null)
        {
            ClaimsIdentity identity = ValidateX509Certificate(x509);
            return new AuthenticationTicket(identity, new AuthenticationProperties());
        }
        else
        {
            return new AuthenticationTicket(null, new AuthenticationProperties());
        }
    }

    private ClaimsIdentity ValidateX509Certificate(X509Certificate2 x509)
    {
        var chain = new X509Chain(true);
        chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline;
        chain.Build(x509);

        X509Certificate2 citizenCertificate = chain.ChainElements[0].Certificate;

        if (citizenCertificate.NotAfter  DateTime.Now)
            throw new Exception("The citizen certificate is not (longer) valid.");

        //TODO verify if citizen certificate has not been revoked

        if (chain.ChainElements[1].Certificate.Thumbprint != "74CC6E5559FFD7C2DD0526C0C21593C56C9384F3")
            throw new Exception("Invalid Citizen CA certificate.");

        if (chain.ChainElements[2].Certificate.Thumbprint != "51CCA0710AF7733D34ACDC1945099F435C7FC59F")
            throw new Exception("Invalid Belgium Root CA certificate.");

        string firstName = Regex.Match(citizenCertificate.Subject, "G=([^,]*),").Groups[1].Value;
        string lastName = Regex.Match(citizenCertificate.Subject, "SN=([^,]*),").Groups[1].Value;
        string nationalRegisterIdentificationNumber = Regex.Match(citizenCertificate.Subject, "SERIALNUMBER=([^,]*),").Groups[1].Value;
        string nationality = Regex.Match(citizenCertificate.Subject, "C=([^,]*)").Groups[1].Value;

        // Based on information of: https://www.ksz-bcss.fgov.be/nl/bcss/page/content/websites/belgium/services/docutheque/technical_faq/faq_5.html
        bool isMale = int.Parse(nationalRegisterIdentificationNumber.Substring(6, 3)) % 2 == 1;

        ClaimsIdentity identity = new ClaimsIdentity(Options.SignInAsAuthenticationType);
        identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, firstName + " " + lastName, null, Options.AuthenticationType));
        identity.AddClaim(new Claim(ClaimTypes.GivenName, firstName));
        identity.AddClaim(new Claim(ClaimTypes.Name, lastName));
        identity.AddClaim(new Claim(ClaimTypes.Gender, isMale ? "M" : "F"));
        identity.AddClaim(new Claim(ClaimTypes.Country, nationality));

        return identity;
    }
}

And for average Joe programer, this is super easy. All he/she has to add to his "Startup.Auth.cs" file is the following code and he/she can authenticate the users based on the eID card.

app.UseEidAuthentication(new EidAuthenticationOptions() 
{
	SignInAsAuthenticationType = "Cookies"
});
Advertisements
Categories: C#, eID