Introduction

ASP.NET is the new Web environment from Microsoft that enables developers to provide Web services (and dynamic Web content) using the .NET framework.

As with any project using the .NET framework, you can choose from a number of programming languages to develop your Web services.

In this article, as in the previous one, I will be using the new .NET language C# to share some of my experience in the implementation of an XKMS service.

This article is mainly based on the Release Candidate version of the .NET framework. Be aware the some beta 2 bugs could potentially complicate an XKMS service development.

Note: This article discusses the November 2001 release of my XKMS service. For anyone who used the first release please consult the change log to learn about all the changes between the releases.

Service Architecture

To find the best architecture for this project, I find it easiest to define a basic scenario and then to incrementally add features to it.

In our case, the most basic scenario involves a client that communicates with an XKMS service.

This service could be completely self-contained on a single server, as shown in Figure 1, below.


Figure 1

While it may be perfect as a test platform, centralizing all XKMS functionality into one server would make it difficult to provide a scalable and reliable solution.

Looking at the XKMS specification, we can see that it is divided into two protocols: X-KISS and X-KRSS.

XML Key Information Service Specification (X-KISS) provides Locate and Validate methods.

XML Key Registration Service Specification (X-KRSS) provides Register, Revoke and Recover methods

Following this breakdown we can guess that: a. the number of transactions between the X-KISS and X-KRSS services will be very different, as most transactions will be directed toward the X-KISS tier b. the properties and needs of each service are different:

X-KISS

X-KRSS

read-only access to database

read/write access to database

fast cryptographic signature/verification

hardware security module (HSM) for server generated key pairs

many X-KISS servers in parallel for scalability

limited number of X-KRSS servers


Figure 2

So the segregation of X-KISS and X-KRSS offers many advantages, mainly:

This is the approach taken by my current XKMS service.

Actually, there is only a proxy. (We'll see later that there is a good reason for this.) The actual XKMS service could easily be deployed on many computers. I don't have many machines, but I can simulate many machines using virtual machines like the one provided by VMWare Workstation software [VMWare]).


Figure 3

Until now all models are very similar to traditional PKI (e.g. X509), but this is only the beginning as there is much more flexibility at hand.

One approach that looks very promising involves using an intelligent XKMS proxy that can forward requests to the proper XKMS service based on an organization's policy.


Figure 4

The XKMS "A" service could be in-house or outsourced, or more interestingly, an organization could switch XKMS provider (outsourcing, in-sourcing or just plain switching) anytime by adjusting their XKMS proxy rules. All of their current key pair would remain valid until the end of their normal lifespan, but no new key pair would be registered in the older provider.

This is the model, which will very likely affect the future development of my service.

The most interesting part of these scenarios is that the client is never affected by the complexity behind the service it trusts.

Challenges

Speaking of trust, all models suffer the same drawback: you must trust the service.

While this may be considered normal in theX.509 world, you must remember that the X509 Root CA's are normally offline, and are therefore much more easier to protect. By contrast, the XKMS service must always be online.

What does that mean? Well it means that the only way to trust the service is to trust its signature (that is, its private key). An XKMS client will use the Validate method to decide to trust or not trust other key pairs. So the Validate result must be trusted somehow (note that this also involves trusting every X-KISS service).

How can we minimize the risks of compromising the service's private key?

  1. Don't use one (i.e. don't sign the validate responses).
    Bad: How can we be sure of the ValidateResult response integrity? Without this signature we can't talk about trust!
  2. Get it offline, part 1: Include a X509 certificate and CRL in the validate signature (signed by an offline "root" key pair).
    Bad: We don't want any dependencies on other technologies such as X509 certificates.
  3. Get it offline, part 2: SAML - XTAML (Trust Axiom).
    Bad: Interesting but not there yet

How can we distribute (and hopefully update) the service's public key?

  1. Embed the public key into the software.
    Bad: The software/client is bound to a single service.
  2. Embed the service public key into a token (e.g. a smart card).
    Bad: The infrastructure isn't yet in place for such a deployment.

To be honest this isn't the kind of problem that really bothers me, at least not right now. But in my opinion, the response to this problem will probably determine the technical success or failure of XKMS (or other online trust technologies) over X509. But enough theory for today - let's get technical!

Implementing an XKMS Service

When I started this project my initial requirements were to:

This quickly evolved into:

Now, let's get started by using the Web Services Description Language (WSDL) to generate some code. . . . .

Importing WSDL

The easiest way to start the project is to use the Microsoft WSDL.EXE tool to generate a stub for the service. (If you would like to know more about WSDL, see the W3C WSDL specification.) This is very similar to generating a stub for the XKMS client. (see Importing a WSDL file for details about how to import the XKMS.WSDL into VisualStudio for an XKMS client application). In our case, we just run the following in a command prompt.
wsdl /server http://www.xmltrustcenter.org/xkms/dotnet/resources/XMLKeyManagement.wsdl /out:server.cs
As Iam upgrading my service from beta 2, I didn't use the new WSDL.EXE generated stub. This would have required a lot of changes in my service and still wouldn't have solved all my problems. Some of the sample code in this article may not exactly reflect the code that you can generate using these tools.

Database Independence

If there is something I dislike, it's finding database code all around a project. This is not a problem with ADO.NET which does a good job of providing RDBMS (and other type of data) independence. The problem is that it breaks the logic flow. However making a class for about every table isn't something terribly interesting either. I think I've found out a useful tool to generate classes from database tables [CODEGEN].

Performance Issues

XKMS is stateless

XKMS is stateless. This means that the service doesn't have to remember a client state between requests. This isn't an issue with ASP.NET as, by default, all Web methods are stateless. [ WebMethod(Description="Register a keypair", EnableSession=false) ] public void Register( ... ) Example for manually setting the Register method to stateless (default)

Cryptographic operations

In general we could say that cryptography is not fast. This gets more critical when we talk about asymmetric cryptography. Since we will be doing cryptographic operations, some steps should be taken to limit the impact of the XKMS service on a computer. 1. Do not generate key pairs on the server 2. Limit the size of the key pair registered by the client (as you may have to verify their signature on some requests later) 3. Choose your authority signing key size carefully. Choose one that is sustainable for your server operation and secure enough to provide trust in your service In a real world (i.e. commercial) service, hardware assisted cryptography (using an HSM, Hardware Security Module, or a simple SSL accelerator) can make a big performance difference on a server by offloading all cryptographic operations. However the cost is much too high for a low volume interoperability service. If you're tempted by hardware acceleration, be aware that Microsoft doesn't support the PKCS#11 interface in their products. Most cryptography from Microsoft products comes from CryptoAPI, which is also the base of most cryptography in the .NET framework (except for a few algorithms implemented in managed code). With CryptoAPI, the interface for hardware assisted cryptography is a "Cryptographic Service Provider" (CSP) and is limited to the Windows world. As Microsoft is a latecomer in PKI many products, particularly high-end HSM, are often only supported using PKCS#11. The situation is slowly evolving toward vendors supporting both PKCS#11 and CSP for their products. Hint: Someone ought to extend the .NET cryptographic classes to support PKCS#11 tokens.

Handling Exceptions

One of the first things you may want to do in each of the service methods is to trap all exceptions and send back a meaningful SOAP response. Of course we'll like to do so without too many constraints. The easiest way to achieve this is to modify (you could also derive a new class) the ErrorInfoType class (generated by the WSDL utility) and add a new constructor accepting an exception.
[System.Xml.Serialization.XmlTypeAttribute (Namespace="http://www.xkms.org/schema/xkms-2001-01-20")]
public class ErrorInfoType
{
	// ... some code ommited for clarity ...
	
	public ErrorIntoType()
	{
	}

	public ErrorInfoType( Exception e )
	{
		errorCode = e.Message;
		ErrorDescription = e.ToString();
	}
}

Depending of your WSDL file and version of VisualStudio.NET you may have to change all method definitions (as well as source). Do this by adding a new "out" parameter ErrorInfo that, under normal circumstance, is null. Then (this is for everyone!) inside each exported method we trap every exception and return them as a ErrorInfoType error.

[ WebMethod(Description="Locate a keypair", EnableSession=false) ]
	[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.xkms.org/schema/xkms-2001-01-20/Locate", 
	RequestNamespace="http://www.xkms.org/schema/xkms-2001-01-20", ResponseElementName="LocateResult", 
	ResponseNamespace="http://www.xkms.org/schema/xkms-2001-01-20", Use=System.Web.Services.Description.SoapBindingUse.Literal, 
	ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped) ]
public void Locate(
	[System.Xml.Serialization.XmlElementAttribute(IsNullable=false)]   
	ref string TransactionID,   
	XmlElement Query,   
	string[] Respond,   
	out string Result,   
	[System.Xml.Serialization.XmlElementAttribute(IsNullable=false)]   
	out XmlElement Answer,
	[System.Xml.Serialization.XmlElementAttribute(IsNullable=false)]   
	out ErrorInfoType ErrorInfo )
{   
   // default value to return   
   Result = "Failure";   
   Answer = null;   
   ErrorInfo = null;   
   try
   {
      // !!! fault injection !!! only for debugging purpose !!!      
      // this line will provoke an exception (as Answer is null)      
      if ( Answer.BaseURI == "allo" )          Answer = null;   
   }   
   catch( Exception e )   
   {
      Result = "Failure";
      Answer = null;
      ErrorInfo = new ErrorInfoType( e ); 
   }
}

Certificate Generation

Are certificates required in an XKMS world? Yes and no. This all depends on your definition of certificates. If you think about it, a certificate is just a public key along with some attributes signed by someone (hopefully someone you trust). A "Validate" response from an XKMS service provides almost the same information as a more common X509 certificate. So yes we need "certificates", but XKMS doesn't need X509 (or PGP, SPKI, ...) certificates. So should an XKMS service support certificates? The answer to that question depends on how you intend to use XKMS. I decided early that compatibility with X509 certificates was a "must have" requirement. But again, nothing mandates that an XKMS service support anything other than KeyNames.

X.509 Certificates

The first, non-public, version of the service used CryptoAPI (in an unmanaged C DLL) to generate the X509v3 certificates.

This worked well, except that most ASP.NET hosts don't accept unmanaged (like C) code on their server. As I understand their concern, I have re-written all certificate generation routines in C#. Guess what? The total SLOC (source line of code) for ASN.1/X509v3 generation is equal to the SLOC of the rest of the XKMS service.

Hopefully the .NET framework includes a (basic, but useful) class to decode X.509 certificates, so all this additional code doesn't affect the XKMS client. At least I now have a 100% managed code Web service (and it made me remember why I found all this XML stuff interesting to begin with).

Other Certificates

Many other types of certificates (like PGP certificates and SPKI are supported in XML Signature [XMLDSIG]). Future version of the service may include support for them. The biggest benefit would be to enable users to receive multiple certificates formats using the same key pair in a single operation.

Signing SOAP Responses

XKMS responses can be signed if the client request contains a "SignedResult" respond string element. Validate methods can always be signed by the service. How can we sign the XML document if we are only working with C# parameters? Well we can't, at least not at the Web method level, but we must prepare for the message signature. To manipulate the SOAP response we must write a SOAP extension [SOAPEXT], which is simply a descendant of the SoapExtension class. There are two difficulties in signing the SOAP response.

Communication between the response and the SOAP extension

Calling a SOAP extension is simple; you just have to add its attribute before the method definition (see source code). Attributes can have parameters but all of them must be static (they cannot be changed inside your method). Hence we need some other form of communication between the method and the SOAP extensions, because the "SignedResult" element is part of the request not of the response. We can't sign in the method but we can prepare for it. We prepare for the signature by adding an element, Signature, in the method definition. The presence, or lack of, determines whether the SOAP extension must, or should not, sign the SOAP response. This makes it easy for the SOAP extension to take action on each response without any direct communication with every XKMS method. Note: The signature element may already be present as a parameter (or as a member of a parameter) depending on which WSDL file and which version of VisualStudio.NET that you used to create your service stub. You can replace this parameter as shown in the sample as there is no way AFAIK to sign the XML response inside the web method.
[ XKMSSigningExtension() ]
public void Validate(	
	[System.Xml.Serialization.XmlElementAttribute(IsNullable=false)]  	
	KeyBindingType Query,   	
	string[] Respond,   	
	out string Result,
   	[System.Xml.Serialization.XmlArrayAttribute(IsNullable=false)]
   	[System.Xml.Serialization.XmlArrayItemAttribute("KeyBinding", IsNullable=false)]   	
	out KeyBindingType[] Answer,
	[System.Xml.Serialization.XmlElementAttribute(IsNullable=false)]   	
	out ErrorInfoType ErrorInfo,
	[System.Xml.Serialization.XmlElementAttribute(IsNullable=false)]   	
	out string Signature )
{
	Result = "Success";	
	Answer = null;	
	ErrorInfoType = null;	
	Signature = "";	
	// this will add a <Signature />
	element in the XML document.	
	// Signature = null;	
	// this wouldn't add the Signature element in the XML document.
}

Source code - Modified Validate Method Definition for enabling Signature

Knowing what to sign

Getting the output of the Web method is fairly easy using the .NET samples. However you must only sign the XML response not the SOAP message. This means that you must "unenvelope" the response (removing the SOAP:Envelope and SOAP:Body ), sign the XML document with the service key, and envelope it back (re-adding the SOAP:Envelope and SOAP:Body) before returning it to ASP.NET.

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ValidateResult xmlns="http://www.xkms.org/schema/xkms-2001-01-20">
<--- ... -- >
</ValidateResult>
</soap:Body>
</soap:Envelope>

Enveloped SOAP message (as received by the SOAP extension)

<ValidateResult xmlns="http://www.xkms.org/schema/xkms-2001-01-20">
<--- ... -- >
</ValidateResult>

XKMS response to be signed (un-enveloped SOAP message)

Take a look at the article Signing XML Documents in the .Net Framework for how to create an enveloped signature with the framework. ASP.NET does a good job from shielding the developers from the actual SOAP transaction. This means that you normally never see the actual output of a service, which is troublesome not only for an XKMS services but all web service that want to sign their responses.

Debugging

Two tools are indispensable for debugging a web service.

DebugView [DBGVIEW] (or another similar tool) which redirects all OutputDebugString (a.k.a. System.Diagnostics.Debug.WriteLine( ... ) in the framework);

A utility to send a predefined XML document to the service. This is really useful in (a) automated testing a set of file with known responses and (b) playing back a bogus transaction submitted by a user of your service. The following source code, ZendZoap, is a minimal tool just for these needs.

using System;
using System.IO;

// assembly available with the XKMS client
using poupou.soap.client;

namespace zendzoap
{
   class SendSoap
   {
      static void Usage()
      {
         Console.WriteLine( "\r\nC# Sample ZendZoap  - version 20011112\r\n");
         Console.WriteLine("Usage");
         Console.WriteLine("-----");
         Console.WriteLine("zendzoap service_url action_url xml_doc_file\r\n");
         Console.WriteLine("   service_url     Service URL (e.g. http://www24.brinkster.com/xkms/xkms.aspx)" );
         Console.WriteLine("   action_url      SOAPAction (e.g. http://www.xkms.org/schema/.../Register)" );
         Console.WriteLine("   xml_doc_file    File which contains the XML doc to send to the web service.\r\n");
      }

      [STAThread]
      static void Main(string[] args)
      {
         if ( args.Length < 3 )
            Usage();
         else
         {
            FileStream fs = new FileStream( args[2], FileMode.Open );
            StreamReader sr = new StreamReader(fs);
            string sXml = sr.ReadToEnd();
            fs.Close();

            string sAction = "SOAPAction: \"" + args[1] + "\"";
            SOAPClient soap = new SOAPClient();
            string sResponse = soap.SoapInvoke( args[0], sAction, sXml );
            Console.WriteLine( sResponse );
         }
      }
   }
}

Source code for zendzoap

Hosting

My current hosting solution for the service isn't up to my satisfaction level and may change in the future.

However, hosting at Brinkster is free, so the limitations are understandable, and it works at the level required for interoperability testing.

Please keep in mind that this interoperability service isn't a product or a service that's being sold, but a service to help the community testing the XKMS technology.

Using the Service

Before using the service you'll need a XKMS client. As far as I know, only two clients/SDK's for XKMS are available. The choice between them will largely depend on your programming language interest. Your current choices are:

The following steps are required after setting up your client. The first two steps are required only if the X509 certificates are of any interest to you (and if you use Microsoft Windows). As an alternative you can receive these certificates by asking for the X509Chain when you register your key pair (but you will still need to install them).

  1. Download, install and trust the "root" certificate;
  2. Download and install the "issuing CA" certificates;
  3. Request a key pair with one of the public profiles available (http://www24.brinkster.com/xkms/request.aspx);
  4. Use the samples provided with the client to generate (like mxkeygen) then register your key pair (like mxregister);

(Note that you do not need to perform steps 1-3 if you use VeriSign's SDK. The SDK contains the required certificates and uses them transparently. VeriSign's SampleXKMSClient provides a command for generating keys.See the README in VeriSign's XKMS SDK 1.0.1 for installation details.)

Current service profiles

Currently certificates for three public profiles can be registered by this service (consult http://www24.brinkster.com/xkms/request.aspx for an up-to-date list of public profiles). All are based on X509 certificates but can be used for other means if required.

  1. Secure Email Service
    Supporting both RSA and DSA key pairs up to 1024bits, X509v3 certificates, 30 days validity.
    CRL are published 3 times a day (every 8 hours).
  2. Secure Web Server Service
    Supporting RSA key pairs up to 1024 bits, X509v3 certificates, 30 days validity.
    CRL are published every day (every 24 hours).
  3. Code Signing Service
    Supporting RSA key pairs up to 1024 bits, X509v3 certificates, 30 days validity.
    CRL are published 2 times a day (every 12 hours).

Note: Due to the performance impact of the feature, none of these profiles support server-side key generation and/or key recovery. However, a new profile may be added to support this feature in a future release of the service.

Features not available using the public service

Some of the developed features couldn't be deployed on my host and so are not publicly available. Just because I can't show them doesn't mean I can't talk about them!

My current host doesn't support SSL. But there is a simple yet secure way to simultaneously host pages in both HTTP and HTTPS. This little code snippet can switch a browser from an unsecured connection to a secure connection. In this case it forces the user to use HTTPS to request an authentication code. The same logic can be applied to refuse some XKMS request (like X-KRSS methods) if they are not sent using HTTPS.

string sSecureURL = "https://www24.brinkster.com/xkms/request.aspx";
if ( ! Request.IsSecureConnection )
	Response.Redirect( sSecureURL, true );

Sample Code - Redirecting to a secure page

Another cool thing that can easily be done using your own server is to return an Authentication Code only for valid Windows NT/2000 users using the NTLM challenge-response feature of Internet Explorer. This could help some auto-enrollment scenarios for organization using IE and IIS.

Futures

My service is not nearly complete.

First, the XKMS specification isn't final and there is still much room for improvement in the actual service, such as:

Conclusions

ASP.NET shields the developer from many details, like XML and SOAP handling (using the WSL generated service stub), XMLDSIG using the .NET framework classes, and database independant access classes.

Using the classes provided by the .NET framework, XKMS itself isn't overly complex to implement.

The most complex part of my service lies in the certificate generation code, which is totally optional for an XKMS service.

Up to now my main objective in this project has been interoperability, both intra-XKMS interoperability (my client/service with other clients/services) and XKMS interoperability with PKIX.

So has interoperability been achieved? No. There are just not enough publicly-available services to justify the "interoperable" stamp. Neither Verisign's service nor mine supports key recovery, and Entrust's service is limited to key registration and key location.

Also, the ability to query a key using one a key's properties (such as KeyName orKeyValue) can be very different between services. This fact somtimes constrains a service's consumers to use the "least common denominator" approach.

Can interoperability be reached ? There are positive signs:

  1. The XKMS specification is simpler than most other similar services (e.g. PKIX, OpenPGP);
  2. The XKMS specification relies on a rather small list of other specification (XML, SOAP, XMLDSIG);
  3. The frequency of service update is rapid and each iteration gets better (i.e. it's convergeing rather than divergeing);

. . .and some negative signs:

  1. After one year, no service support every aspect of the XKMS 1.0 specification
  2. Currently, no XKMS service complies fully with the specification

Given the simplicity of the XKMS specification and the fact that it builds on standards not known to be problematic (like. X.500, X.509 DN) I expect interoperability to improve gradually over the next year. It is reasonable to think that once XKMS becomes a W3C recommendation many interoperable products and services will be available to the public.

Somewhere on the road I've become more and more interested about the potential XKMS "as-is", that is, in XKMS using only XML/XMLDSIG and not relying on X509 or PKIX, and how organizations could benefit from its implementation.

Most Web developers have a good understanding of XML, and many new Web applications will be developed as Web services. It's good to know to XKMS can help those developers build secure applications using tools they understand, rather than force Web applications or services to include obscure API's, proprietary toolkits, and weird formats (i.e. ASN.1).

Resources

[CODEGEN]
C# Code Generator by Gfw, http://yzcsharp.yyyz.net/
[DBGVIEW]
Sysinternals DebugView, http://www.sysinternals.com/ntw2k/freeware/debugview.shtml
[SOAPEXT]
MSDN Library, Fun with SOAP Extensions, http://msdn.microsoft.com/library/en-us/dnaspnet/html/asp03222001.asp
[VMWARE]
VMWare Workstation, http://www.vmware.com
[XKMS]
XML Key Management Specification, http://www.xmltrustcenter.org/
[XMLDSIG]
XML Signature Work Group, http://www.w3.org/Signature/Overview.html
[XTAML]
XML Trust Axiom Markup Language, http://www.xmltrustcenter.org/research/xtaml/index.htm

About the author

Sébastien Pouliot is a Security Architect for Motus Technologies, Québec, Canada where he designs security products and consults in PKI and IT security with government agencies.

His previous works includes implementation of standards regarding cryptography and smart cards, biometrics technologies, custom PKI designs for specific markets, and many security related projects as an employee of the Canadian Department of National Defense.

He can be reached at spouliot@motus.com.