Compiling and Installing ZXID

Sampo Kellomäki ( Identity Management toolkit implements standalone SAML 2.0 and Liberty ID-WSF 2.0 stacks. This document explains how to compile ZXID from source code.

1 Introduction

ZXID is distributed in source code form, ready to be compiled with C development environment.

Depending on your skill level, you may want to see if a binary package is available for your distribution - installing them is similar to installing the versions compiled from source, except that you step the early steps of compilation.

Once you have compiled ZXID or found a package, you should proceed to install ZXID. This will depend heavily on your environment and some of the cases are explained in their own documents.

After installation, you should try to run a canned tutorial, in section <<see:>>, below, to learn the basics of the technology and to ascertain everything works.

When you are ready to deploy your own services, you should check configuration instructions in ZXID Configuration Reference.

1.1 Other documents

2 Installing

If you want to try ZXID out immediately, we recommend compiling the library and examples and installing one of the examples as a CGI script in an existing web server. See later chapters for more details.

Download from or get it with anon git: git clone git://

  tar xvzf zxid-0.76.tgz
  cd zxid-0.76
  # N.B.  There is no configure script. The Makefile works for all
  #       supported platforms by provision of correct TARGET option.
  # N.B2: We distribute some generated files. If they are missing, you need
  #       to regenerate them: make cleaner; make dep ENA_GEN=1
  # Standard place is /var/zxid. You can change this with, e.g.
  #   make ZXID_PATH=/usr/local/var/zxid
  make                    # default Linux. Do `make TARGET=sol8' for Solaris
  make all                # Also builds the optional language bindings, see below
  make dir                # Creates /var/zxid hierarchy (may need to be root)
  make apachezxid         # optional
  make apachezxid_install # optional: install the mod_auth_saml Apache module
  make samlmod            # optional
  make samlmod_install    # optional: install Net::SAML perl module
  make phpzxid            # optional
  make phpzxid_install    # optional: install PHP extension
  make javazxid           # optional

  cp zxidhlo <webroot>/
  # configure your web server to recognize zxid a CGI, e.g.
  mini_httpd -p 8443 -c 'zxid*' -S -E zxid.pem

  # Edit your /etc/hosts to contain       localhost

  # Point your browser to (zxid_simple() API version)       # Perl version      # PHP version  # Java version

  # Find an IdP to test with and configure it...
  # see zxididp and zxid-idp.pd for documentation, or use the
  # free IdP on the net:

2.1 Prerequisites

This software depends on the following packages:

  1. zlib from Generally whatever comes with your distro is sufficient.

  2. openssl-0.9.8l or openssl-1.0.0c (earlier versions contain a man-in-the-middle security vulnearability) or later. See Generally openssl libraries distributed with most Linux distros are sufficient. ((It is
 possible to compile without OpenSSL, e.g. for space constrained embedded
 system, but this has serious security implications.))

  3. libcurl from I used version 7.15.5, but probably whatever ships with your distribution is fine. libcurl is needed for SOAP bindings and for fetching metadata. It needs to be compiled to support HTTPS. ((Compilation without libcurl is possible
 with some loss of functionality.))

  4. HTTPS capable web server. For most trivial testing CGI support is needed. We recommend mini_httpd(8) available from

    We also provide Apache HTTP receipe: apache.html

  5. Perl, PHP, and Java interfaces depend on the respective development tools but should not need any additional modules or tools.

2.1.1 Building from Source: Install Required Packages

While you may compile the dependency libraries from their respective sources, generally you can use the libraries that come with your operating system distribution. In this case you need to ensure that "development" versions of the packages are installed (the non-development versions do not include header files or .a files, which are needed for compiling zxid).

Unfortunately the manner how development packages are installed is highly distribution dependent. Here are some commands that have been empirically found to work (tested 2011):

  sudo apt-get install libssl-dev     # Debian
  sudo apt-get install libcurl4-openssl-dev
  sudo apt-get install libapr1-dev
  sudo apt-get install apache2-dev
  sudo apt-get install php5-dev
  sudo apt-get install openjdk-6-jdk
  sudo apt-get install mini-httpd     # But our patched version is better

  sudo yum -y install openssl-devel   # Redhat
  sudo yum -y install libcurl-devel

2.1.2 Additional Prerequisites for Complete Rebuild from Scratch

Following additional packages are needed by developers who wish to build from scratch, including the code generation (the standard distribution includes the output of the code generation, so most people do not need these).

  1. gperf from (only for build process when generating code)

  2. swig from (only for build process and only if you want scripting interfaces)

  3. perl from (only for build process and only if you want to generate code from .sg)

  4. plaindoc from (only for build process, for code generation from .sg, and for documentation) You can also do git clone git://

Although technically not needed to build zxid, you will need an IdP to test against. You can use the free IdP at - it allows anyone to register a user and any SP to join the Circle of Trust. Or you can compile and configure the zxididp, see zxid-idp.pd.

2.1.3 Operating System and Platform Support

As of January 2011, following platforms are "officially" supported:

Many other platforms have been occasionally tested and found to work, such as

As of April 2013 most testing has been on x86_32 and x86_64 architectures. The code is believed to be 64bit clean. Most testing has been in little endian (ix86) architectures, with only occasional testing in big endian architectures like PowerPC and Sparc. Never-the-less, we are committed to support every modern architecture and OS out there.

N.B. We prefer to support every supported architecture via an explicit make TARGET=yourarch section in the Makefile. We believe debugging gnu autohell generated configure scripts is more pain and distraction than it's worth. If you add new platform support, please do so directly in the Makefile.

2.2 Canned Tutorial: Running ZXID as CGI under mini_httpd

While zxid will run easily under Apache httpd (see recipe), for sake of simplicity we first illustrate running it with mini_httpd(8), a very simple SSL capable web server by Jef Poskanzer.

2.2.1 Getting and installing mini_httpd

You can download the source for mini_httpd from

You should already have installed OpenSSL, or quite probably OpenSSL shipped with your distribution. If it is not located at /usr/local/ssl, the you need to edit the mini_httpd Makefile to indicate where it is. At any rate you need to uncomment all lines that start by SSL_ in the Makefile. Then say


Now copy the mini_httpd binary somewhere in your path.

2.2.2 Running mini_httpd

After building zxid, cd to zxid directory and run

  mini_httpd -p 8443 -c 'zxid*' -S -E zxid.pem


  -p 8443      specifies the port to listen to
  -c 'zxid*'   specifies that URL paths with "zxid" are CGI scripts
  -S           specifies that https is to be used
  -E zxid.pem  specifies the SSL certificate to use

See Apache recipe for alternative that avoids mini_httpd, but is more complicated otherwise.

N.B. The zxid.pem certificate and private key combo is shipped with zxid for demonstration purposes. Obviously everybody who downloads zxid has that private key, so there is no real security what-so-ever. For production use, you must generate, or acquire, your own private key-certificate pair (and keep the private key secret). See Certificates chapter for further info.

2.2.3 Accessing ZXID

Edit your /etc/hosts file so that the definition of localhost also includes and domain names, e.g:       localhost

Point your browser to

or if you do not want the common domain cookie check

Dynamic linking problems

If accessing the URL (while running mini_httpd) you get no error message and no content - everything just mysteriously fails - you may be hitting a dynamic linking problem. If mini_httpd(8) fails to launch CGI script it will silently fail. This is unfortunate, but I guess that is what the "mini" in the name implies.

To make matters even worse, mini_httpd(8), probably in the interest of security, will ignore LD_LIBRARY_PATH variable. Apparently it has its fixed notion of the library paths that is set at compile time.

If you suspect this problem, try following:

  1. Create shell script called

         echo Content-Type: text/plain
         echo Test $$
         echo lib_path is --$LD_LIBRARY_PATH--
         ldd zxidhlo
         ./zxidhlo -h 2>&1
         echo Exit value --$?--
  2. Restart mini_httpd(8) like this

         chmod a+x
         mini_httpd -p 8443 -c -S -E zxid.pem -l mini.out
  3. Access - you may see something like

         Test 1655
         lib_path is --/usr/local/lib:/usr/lib--
         ./zxidhlo: error while loading shared libraries: cannot
             open shared object file: No such file or directory

    Now you at least see why it's failing (in this case the directory where libcurl was installed is not in mini_httpd's notion of LD_LIBRARY_PATH). If the zxidhlo binary runs fine from comman line, try `ldd zxidhlo' to see where it is finding its libraries.

Easiest dirty fix is to copy the missing libraries to one of the hardwired directories of mini_httpd(8) (e.g. /usr/lib). More sophisticated fixes include using ldconfig(8), recompiling your mini_httpd(8), or statically linking the offending library into zxidhlo binary.

2.2.4 Setting up an IdP

ZXID now ships with an IdP: zxididp. You may set this up, see documentation in zxid-idp.pd, or you may want to use a free IdP on the net, such as

For you to test zxidhlo, you will need to acquire an IdP from somewhere - any vendor whose product is SAML 2.0 certified will do. Possible sources are

If you do not want to install an IdP yourself (even for testing), find someone who already runs one (e.g. and ask if they would be willing to load the metadata of your zxid SP. If you do this, you will need to get externally visible domain names. This canned tutorial uses /etc/hosts (see previous step) which is only visible on your own machine.

Once you get your IdP up and running, you need to make sure it accepts the zxid SP in its Circle of Trust (CoT). This is done by placing the metadata of the SP in right place in the IdP product configuration. If your IdP supports automatic CoT management, just turn it on and chances are you are done. ((On production IdP you should
 understand the trust implications (i.e. no trust) of flipping automatic
 CoT management on.))

If not, you can obtain the zxid SP metadata (which is slightly different for each install so you can't just copy it from existing install) from

This URL is the well known location method metadata URL. It is also the SP Entity ID or Provider ID, should the IdP product ask for this in its configuration. If the IdP product needs you to supply the metadata manually as an xml file, just point your web browser to the above URL and save to file, or use curl(1) or wget(1).

zxid SP, by default, has automatic fetching of IdP metadata enabled so there is no manual configuration step needed, provided that the IdP supports the well known location method. All SAML 2.0 certified IdP implementations must support it (but you may still need to enable it in configuration). See [SAML2meta] section 4.1 "Publication and Resolution via Well-Known Location", p.29, for normative description of this method.

However, you will need the Entity ID (Provider ID) of the IdP. This is the URL that the IdP uses for well known location method of metadata sharing. You may need to dig the IdP documentation or GUI for a while to find it. If you already have the IdP metadata as an xml file, open it and look for EntityDescriptor/entityID. If you already have the file, you can also import it manually by running the following command

  ./zxcot -a </path/to/idp-meta.xml

But the preferred method still is: just let the automatic method do its job. See also zxcot(8) documentation, or run zxcot -h

2.2.5 Your first SSO

  1. Start at


    If you had common domain cookie already in place, and you are already logged in the IdP, the SSO may happen automatically (go to step 3). The automatic experience will be typical when you use SSO regularly for more than one web site (i.e. several SPs).

    However, if you get a screen titled "ZXID SP SSO", you need to paste the IdP's Entity ID to the supplied field and click "Login". If zxid SP already obtained the metadata for the IdP, you may also see a button specific for your IdP (and in this case there is no need to know the Entity ID anymore or paste anything).

  2. Next step depends on the IdP product you are using. Usually a login screen will appear asking for user name and password. Supply these and login. You will need an account at the IdP.

  3. For more slick IdPs, that's all you need to do and you will land right back at the zxid SP page titled "ZXID SP Management".

    Congratulations, you have made your first SSO!

    However, some IdPs will pester you with additional questions and you will have to jump through their hoops. A typical question is whether you want to accept a federation. You do.

    Sometimes the federation question does not appear automatically and you need to figure out a way to create a federation in their user interface and how to get them to send you back to the SP. Sometimes the word used is "account linking" instead of federation. ((Vendor products are constantly
 improving in this area. From protocol perspective
 all the additional gyrations are unnecessary. Be sure
 to provide feedback to the vendor so that simpler, easier
 to use, products will emerge in future.))

3 Compilation for Experts

  make cleaner
  make dep ENA_GEN=1
  make all ENA_GEN=1

3.1 Build Process

The build process of ZXID relies heavily on code generation techniques that are not for the faint of heart. Some of these techniques, like were innovated for this project, while others like SWIG and gperf(1) are existing software. Here and there some additional perl(1)  ((There used to be a <i>sed(1)</i> dependency as well, but
 nowdays <tt></tt> perl script handles all seddish stuff.)) scripts are run to fix a thing or two.

Fig-1: ZXID Build Process

Carefully study the Makefile, and this should all start to make sense (no pun intended). Please note that there is no configure script and GNU Auto-tools ("GNU Autohell") are not used. This is because they have been evaluated to be unsuitable for this project (or to author's tastes). If the Makefile does not do what you want, you should first study if you can change necessary variables using, or if that does not work, then just edit the Makefile itself.

To make your life easier, the build process is not recursive and only uses single Makefile, so if you edit it, you can just say make -f MyMakefile

You can temporarily customize the Makefile variables by providing a new value on command line, e.g.

  make CC=cc   # override the default of CC=gcc

Another philosophical tidbit is that, although some source code is in subdirectories, all the build logic is kept in one top level Makefile, eliminating all the complexity of hierarchical make. The Makefile supports building outside source tree using vpath feature of gnu make(1).

3.2 Special or embedded compile (reduced functionality)

libzxid contains thousands of functions and any given application is unlikely to use them all. Thus the easiest, safest, no loss of functionality, way to reduce the footprint is to simply enable compiler and linker flags that support dead function elimination. ((Unfortunately the gnu ld does not support dead
 function elimination. You should file this as a bug to them. If they
 tell you to put every one of the 7000-some functions in a separate <tt>.c</tt> file,
 consider the scalability implications of this. Read the comments in
 <tt></tt> for a full scoop and an approach.))

On gcc you should investigate compilation with "-ffunction-sections -fdata-sections" and linking with "-Wl,--gc-sections".

If you need to squeeze zxid into as minimal space as possible, some functionality trade-offs are supported. I stress that you should only attempt these trade-offs once you are familiar with zxid and know what you are doing. The canned install instructions and tutorial walk thrus stop working if you omit significant functionality.

3.2.1 Compilation without OpenSSL

Comment out the -DUSE_OPENSSL flag from CFLAGS in Makefile and recompile.

This will cripple zxid from security perspective because it will no longer be able to verify or generate digital signatures. Unless your environment does not need trust and security, or you understand thoroughly how to provide trust and security by other means, it is a very bad idea to compile without OpenSSL.

N.B. Compiling, or not, zxid with OpenSSL does not affect whether your web server will use SSL or TLS. Unless you know what you are doing, you should be using SSL at web server layer. Given that SSL is used at web server layer, the memory footprint savings you would gain from compiling zxid without OpenSSL may be negligible if you use dynamic linking.

3.2.2 Compilation without libcurl

Comment out the -DUSE_CURL flag from CFLAGS in Makefile and recompile.

Disabling libcurl does not have adverse security implications: you only loose some functionality and depending on your situation you may well be able to live without it.

  1. Without libcurl, zxid can not act as a SOAP client. This has a few consequences

    1. Artifact profile for SSO is not supported because it needs SOAP to resolve the artifact. In most cases a perfectly viable alternative is to use POST profile for SSO.

    2. SOAP profiles for Single Logout and NameID management (aka defederation) are not supported. You can use the redirect profiles and get mostly the same functionality.

    3. ID-WSF Web Services Client (WSC) and Discovery Client (DIC), as well as XACML client (PEP) functionality is not available.

  2. Automatic CoT metadata fetching using well known location method is not supported without libcurl. You can fetch the metadata manually, e.g. using web browser, and place it in /var/zxid/cot directory.

    If you want to manually control your Circle of Trust relationships, you probably want to do this anyway so loss of automatic functionality may be a non-issue. ((If you compile with libcurl, but still want to disable
 automatic metadata fetching, investigate the MD_FETCH
 and related configuration options.))

  3. Web Services Client (WSC) functionality is not supported without libcurl. Effectively this is just another case of "SOAP needed". If you have your own SOAP implementation, you may, at lesser automation, achieve much of the same functionality by calling the encoder and decoder functions manually.

3.2.3 Compiling without zlib (not supported)

zlib is used mainly in redirect profiles. Since zlib is widely available and its foot print is small, we have made no supported provision to compile without it. If you hack something together, let us know.

3.3 Static Linking and Building Against Dietlibc

Static linking has its advantages: (i) you eliminate all library dependencies from install process - as well as from error reporting and debugging processes; (ii) you avoid the dynamic linking overhead - this is significant in CGI use where same executable gets launched over and over again. The buffer cache ensures the blocks of dll's (.so's) are already in memory, but that does not prevent the system calls to do the redundant dynamic linking step (just look at output of strace for first about 100 lines on a dynamically linked executable to get an idea). With static link, the buffer cache has the blocks and there is no dynamic link syscall overhead.

Static linking also has its cons: (i) if any library has a bug, such as a critical security vulnearability, then you need to rebuild (and reinstall in all places where it was distributed) the statically linked binary - it is not enough to upgrade the offending library package. But this sword cuts the other way too: you will always know what combination of libraries is being used (because you built it and you kept records), thus any bugs that are due to interactions between versions of libraries are none of your concern.

(ii) Static linking prevents some techniques adopted by modern libraries, such as gnu libc. For example, name resolution can not dynamically load resolver modules so you probably have to forget about YP (Sun Yellow Pages) or NIS (Sun Network Information Service - a newer version of YP) support. Your /etc/nsswitch.conf will no longer be consulted. Instead you will have a fixed static name resolution policy: first check /etc/hosts, then DNS. Heck, some of us wanted that to start with - sounds like an improvement.

In bug reduction, minimality is a good thing. glibc has gotten about as far as possible from minimality. Luckily, competing libc projects have appeared. Felix Leitner's dietlibc ( is perhaps the most promising candidate.

Dietlibc is useful for compiling statically linked binaries without glibc dependency. The dependency is to be avoided for two reasons: (i) statically linked glibc still needs dynamic linking for name resolution, (ii) dietlibc is a different code base than glibc. glibc is a fat target while dietlibc is used by security conscious minority - thus it is not likely to be an attractive target.

3.3.1 dietlibc-0.33 Build

wget tar xvf dietlibc-0.33.tar.bz2

N.B. Enabling WANT_DYNAMIC may trigger "no .eh_frame_hdr table will be created" linking error.

diff -u dietfeatures.h~ dietfeatures.h
--- dietfeatures.h~     2012-11-02 11:17:28.000000000 +0000
+++ dietfeatures.h      2013-04-13 17:47:37.000000000 +0000
@@ -4,8 +4,8 @@
 /* feel free to comment some of these out to reduce code size */

 /* #define WANT_ERROR_PRINTF */
@@ -29,7 +29,7 @@
 #define WANT_TLS

 /* make the startcode, etc. dynamic aware ({con,de}structors) */
 /* #define WANT_DYNAMIC */

 /* GDB support in the dynamic linker */
@@ -46,23 +46,23 @@
 /* 20040118: enabling this breaks User Mode Linux!  It's their fault. */


 /* you need to define this if you want to run your programs with large
  * file support on kernel 2.2 or 2.0 */

 /* do you want localtime(3) to read /etc/localtime?
  * Needed for daylight saving time etc. */

 /* do you want the DNS routines to parse and use "domain" and "search"
  * lines from /etc/resolv.conf?  Normally not used on boot floppies and
  * embedded environments. */

 /* do you want IPv6 transport support in the DNS resolver? */
-#define WANT_IPV6_DNS
+/*#define WANT_IPV6_DNS*/

 /* do you want gethostbyname and friends to consult /etc/hosts? */
@@ -72,10 +72,10 @@

 /* do you want math functions high precision rather than fast/small? */

 /* do you want support for matherr? */
+/*#define WANT_MATHERR*/

 /* do you want crypt(3) to use MD5 if the salt starts with "$1$"? */
 #define WANT_CRYPT_MD5
@@ -87,11 +87,11 @@
 /* This enables zeroconf DNS aka Rendezvous aka Bonjour. */
 /* This code will try zeroconf DNS if you ask for host.local or if you
  * ask for an unqualified hostname */
+/*#define WANT_PLUGPLAY_DNS*/

 /* This enables LLMNR, the MS variant of zeroconf DNS.  This only works
  * if you also enabled WANT_PLUGPLAY_DNS */
-#define WANT_LLMNR
+/*#define WANT_LLMNR*/

 /* Uncomment this if you want DNS lookups to fail if /etc/hosts contains
  * an entry but it's for a different record type */
@@ -101,7 +101,7 @@
  * check for valgrind, and if detected, turn off optimized SIMD string
  * routines that cause false positives in valgrind.  This enlarges and
  * slightly slows down your code! */

 /* do you want that malloc(0) return a pointer to a "zero-length" object
  * that is realloc-able; means realloc(..,size) gives a NEW object (like a
@@ -129,7 +129,7 @@
  * and program_invocation_name to be there.  This functionality is not
  * portable and adds useless bloat to libc.  Help stomp out code
  * depending on this!  util-linux, I'm looking at you here! */

 /* Include support for ProPolice/SSP, calls guard_setup */
 /* ProPolice is part of gcc 4.1 and up, there were patches for earlier

diff -u Makefile~ Makefile
--- Makefile~   2006-06-18 14:32:28.000000000 -0400
+++ Makefile    2006-12-16 22:34:24.000000000 -0500
@@ -141,6 +141,7 @@
 CFLAGS += -Wall -W -Wchar-subscripts -Wmissing-prototypes -Wmissing-declarations -Wno-switch -Wno-unused -Wredundant-decls
+CFLAGS += -march=i586
 PWD=$(shell pwd)

diff -u libcruft/res_query.c~ libcruft/res_query.c
--- libcruft/res_query.c~       2006-12-08 16:24:56.000000000 +0000
+++ libcruft/res_query.c        2008-06-15 18:39:21.000000000 +0000
@@ -106,8 +106,10 @@
       if (duh[1].fd!=-1) {
        sendto(pnpfd,packet,size,0,(struct sockaddr*)(&pnpsa4),sizeof(pnpsa4));
+#ifdef WANT_IPV6_DNS
        if (!v4pnp)
          sendto(pnpfd,packet,size,0,(struct sockaddr*)(&pnpsa6),sizeof(pnpsa6));
       /* if it doesn't work, we don't care */

diff -u /opt/diet/include/sys/param.h~ /opt/diet/include/sys/param.h
--- /opt/diet/include/sys/param.h~      2008-06-15 18:55:43.000000000 +0000
+++ /opt/diet/include/sys/param.h       2008-06-15 20:12:49.000000000 +0000
@@ -26,4 +26,6 @@
 #define roundup(x, y)   ((((x)+((y)-1))/(y))*(y))
 #define powerof2(x)     ((((x)-1)&(x))==0)
+#define        MAXSYMLINKS     20

diff -u dietlibc-0.32/libugly/gethostent.c~ dietlibc-0.32/libugly/gethostent.c
--- libugly/gethostent.c~       2003-06-23 10:48:13.000000000 +0000
+++ libugly/gethostent.c        2010-08-25 00:12:09.000000000 +0000
@@ -26,6 +26,8 @@
   if (!hostmap) {
     int hostfd=open(_PATH_HOSTS,O_RDONLY);
     if (hostfd<0) return 0;
+    /* *** all this global variable manipulation seems rather at odds with reentrant
+     * *** nature of gethostent_r(), surely there is race here. 24.8.2010, */
     if ((long)hostmap==(-1)) { close(hostfd); hostmap=0; goto error; }
@@ -81,8 +83,7 @@
       *dest=0; ++dest;
-    if (*cur=='\n') { ++cur; ++aliasidx; break; }
-    if (cur>=last || !isblank(*cur)) break;
+    if (cur>=last || *cur=='\n') { ++cur; ++aliasidx; break; }

diff -u __v_printf.c.orig __v_printf.c
--- __v_printf.c.orig   2013-04-16 15:13:12.000000000 +0000
+++ __v_printf.c        2013-04-16 16:53:49.000000000 +0000
@@ -7,15 +7,35 @@
 #include "dietstdio.h"
 #include "dietwarning.h"

-#define MAX_WIDTH 10*1024
 static inline unsigned long skip_to(const char *format) {
   unsigned long nr;
   for (nr=0; format[nr] && (format[nr]!='%'); ++nr);
   return nr;

-#define A_WRITE(fn,buf,sz)     ((fn)->put((void*)(buf),(sz),(fn)->data))
+/*#define A_WRITE(fn,buf,sz)   ((fn)->put((void*)(buf),(sz),(fn)->data))*/
+/* 20130416,
+ * Problem: Old A_WRITE() ignores the return value from write(2), thus leaving
+ *     open the possibility that the data was not actually written.
+ * Proposed fix: deal with error return from write style function
+ *     and keep on trying in blocking fashion until everything is written. */
+int __a_write_all(struct arg_printf* fn, const char* buf, unsigned int len) {
+  int ret, todo=len;
+  while (todo) {
+    ret = fn->put((void*)buf, todo, fn->data);
+    if (ret == -1) {
+      switch (errno) {
+      case EAGAIN: /*case EWOULDBLOCK:*/ ret=0; break;
+      default:
+       return ret;
+      }
+    }
+    todo -= ret;
+    buf += ret;
+  }
+  return len;
+#define A_WRITE(fn,buf,sz)     __a_write_all((fn),(buf),(sz))
 #define B_WRITE(fn,buf,sz)     { if ((unsigned long)(sz) > (((unsigned long)(int)(-1))>>1) || len+(int)(sz)MAX_WIDTH) return -1;
        if (ch=='0' && !flag_left) padwith='0';
        goto inn_printf;
@@ -138,7 +157,6 @@
-         if ((width=(unsigned long)tmp)>MAX_WIDTH) return -1;
          goto inn_printf;
       case '.':
@@ -152,7 +170,6 @@
-       if (preci>MAX_WIDTH) return -1;
        goto inn_printf;

       /* print a char or % */

On gcc-3.4.6 you need

diff -u  Makefile~ Makefile
--- Makefile~   2012-11-02 11:17:28.000000000 +0000
+++ Makefile    2013-04-13 19:38:26.000000000 +0000
@@ -141,6 +141,7 @@
 CFLAGS += -W -Wall -Wextra -Wchar-subscripts -Wmissing-prototypes -Wmissing-declarations -Wno-switch -Wno-unused -Wredundant-decls
+CFLAGS += -march=i586

 PWD=$(shell pwd)

@@ -534,7 +535,7 @@
 # This facepalm brought to you by: Ubuntu!
 $(OBJDIR)/stackgap.o: lib/stackgap.c dietfeatures.h
-       $(CROSS)$(CC) $(INC) $(CFLAGS) -c lib/stackgap.c -o $@ -D__dietlibc__ -fno-stack-protector
+       $(CROSS)$(CC) $(INC) $(CFLAGS) -c lib/stackgap.c -o $@ -D__dietlibc__
        $(COMMENT) -$(CROSS)strip -x -R .comment -R .note $@

  patch --dry-run -p0 <the-patch-above-as-needed

After applying patches

  make prefix=/usr/local DEBUG=1
  make prefix=/usr/local DEBUG=1 dyn
  sudo make prefix=/usr/local install  # works

1) || len+(int)(sz)<len) return -1; A_WRITE(fn,buf,sz); } while (0)

 static const char pad_line[2][16]= { "                ", "0000000000000000", };

@@ -123,7 +143,6 @@

       case '9':
        if(flag_dot) return -1;

- if (width>MAX_WIDTH) return -1;

        if (ch=='0' && !flag_left) padwith='0';
        goto inn_printf;

@@ -138,7 +157,6 @@


- if ((width=(unsigned long)tmp)>MAX_WIDTH) return -1;

          goto inn_printf;
       case '.':

@@ -152,7 +170,6 @@


- if (preci>MAX_WIDTH) return -1;

        goto inn_printf;
       /* print a char or % */


3.3.2 zlib-1.2.7 linked against dietlibc

tar xvf zlib-1.2.7.tar.bz2
cd zlib-1.2.7
# diet compile on x86_64 (amd64 as in GQ)
cp contrib/amd64/amd64-match.S ./match.S
CC='diet gcc' LD='diet ld' CFLAGS="-g -O3 -DASMV -D_BSD_SOURCE -DGNU_SOURCE" ./configure --static --prefix=/usr/local
make LOC=-DASMV OBJA=match.o
make test
sudo make install

3.3.3 OpenSSL-1.0.1e linked against dietlibc

  tar xvf openssl-1.0.1e.tar.gz

Add to Configure

  "diet-debug-linux-x86_64","diet gcc:-DREF_CHECK -DCONF_DEBUG -DCRYPTO_MDEBUG -m64 -DL_ENDIAN -DTERMIO -O2 -g -Wall::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_UNROLL:${x86_64_asm}\$(SHLIB_MAJOR).\$(SHLIB_MINOR):::64",

  "diet-debug-linux-pentium", "diet gcc:-DREF_CHECK -DCONF_DEBUG -DL_ENDIAN -DTERMIO -O2 -g -march=pentium  -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",

N.B. -DREF_PRINT causes compilation error.

export PATH=/usr/bin:/bin:/usr/local/bin   # /usr/local/bin is needed for diet(1) to be found
./Configure --prefix=/usr/local enable-rc5 enable-mdc2 no-dso no-hw no-engine zlib diet-debug-linux-pentium
./Configure --prefix=/usr/local enable-rc5 enable-mdc2 no-dso no-hw no-engine zlib diet-debug-linux-x86_64
make depend  # fails
make         # ?

time make test  # segfaults?!?
sudo make install

3.3.4 curl-7.30.0 linked against dietlibc and openssl-1.0.1e

tar xvf curl-7.30.0.tar.bz2
cd curl-7.30.0

CC='diet gcc' LD='diet ld' CPPFLAGS='-I/usr/local/include' LDFLAGS='-L/usr/local/lib' LIBS='-lssl -lcrypto -lz' ./configure --prefix=/usr/local --with-ssl=/usr/local --without-gnutls --enable-thread --enable-nonblocking --disable-shared

make test
sudo make install

3.3.5 zxididp against dietlibc based libraries

  make clean
  CC='diet cc' LD='diet cc' make zxididp-static

  diet gcc -o zxididp zxididp.o -static -L. -lzxid -pthread -lpthread -L/usr/local/lib -L/usr/local/ssl/lib-x86_64 -lcurl -lssl -lcrypto -lz

3.4 Choosing Which Standards to Include (default: all)

WARNING: Only regularly tested configuration is to compile all standards in.

On space constrained systems you may shed additional weight by only compiling in the IdM standards you actually use. Of course, if you do not use them, the dead function elimination should take care of them, but sometimes you can gain additional savings in space and especially compile time.

Another reason could be, in the land of the free, if some modules are covered by a software patent, you may want to compile a binary without the contested functionality. ((Please do not
 ask me to add additional baggage to avoid patents. Software
 patents are a plague and your efforts are best spent in getting
 them overturned or changing laws so they go away.))

You can tweak the flags, shown in accompanying table, in the Makefile or by supplying new values in or on commend line. For example

  make TARGET=sol8 ENA_SAML2=0

would disable SAML 2.0 (and trigger build for Sparc Solaris 8).

Table 1:Conditional inclusion of standards
Makefile flag Standard Comments
ENA_SSO=1 All SSO Must be enabled for any of SSO to work
ENA_SAML2=1 SAML 2.0  
ENA_FF12=1 ID-FF 1.2 Requires ENA_SAML11=1
ENA_SAML11=1 SAML 1.1  
ENA_WSF=1 All WSF Must be enabled for any of WSF to work
ENA_WSF2=1 ID-WSF 2.0  
ENA_WSF11=1 ID-WSF 1.1  


You can use to remember your own make(1) options, such as TARGET and different ENA flags, without editing the distributed Makefile.

One useful option to put in is ENA_GEN which will turn on the dependencies that will trigger generation of the files in zxid/c directory. For example

  echo 'ENA_GEN=1' >>
WARNING: If you are confused about compilation flags appearing "out of nowhere", despite not being mentioned in the Makefile, be sure you have not inadvertently created a (perhaps you rsynced the sources from another machine and forgot to remove A similar problem can occur if you accidentally copied deps.dep from another machine. It will reference the dependencies with the paths of that other machine. Just remove the deps.dep to solve that issue.

3.6 Known Compilation Warnings

This list was reated around August 2010. Things are likely to have changed since then.

  1. __FUNCTION__ definition incompatible with char*. Ignore.

  2. const char *file incompatible with &((const char)file

          zxsig.c:314: warning: passing arg 1 of `ERR_get_error_line_data' from incompatible pointer type
          zxsig.c:314: warning: passing arg 3 of `ERR_get_error_line_data' from incompatible pointer type

    This probably is due to const being, or not, defined differently.


  3. Warning about sentinel: Ignore.

3.7 Tough Compilation Errors

ZXID was mostly developed on gcc 3.4.6 and explicitly has not been tested on 4.x series of gcc (due to deprecation of commonly useful features in that gcc series). If you hit compile time problems with 4.x gcc, try with 3.4.x series gcc first, before reporting bugs.

*** elaborate more - until then, mail the author

3.8 Tough Linking Errors

3.9 Overview of the Tool (guru level)

The tool, distributed as part of Plaindoc ( system, is at the heart of the ZXID code generation. Unfortunately the tool is still in flux. What follows is general outline valid as of March 2007. can be invoked in three ways (see --help), but the invocation of interest to us is the -S (SG to XSD with Code generation mode). This mode takes as inputs all .sg files and names of decoding root elelment. It will generate one mega parser that is capable of decoding any root element (and since root elements contain other elements, then really all elements). The decoder works by recursive descent parser principle so there will be smaller decoder functions to call. Similarily the encoder is generated by creating many unit encoders for different elements. Then the parent elements will call the child element encoders.

3.9.1 Process .sg to create %dt hash (throw away XSD output) first processes the .sg files to XSD. As a side effect it populates %dt multidimentsional hash

  $dt{'attribute'}{attrname} = "";

Where the array-of-subelems-and-attrs can contain tag or reference to fundamental or derived type, e.g.


3.9.2 The expanding element definitions in %dt

Since the concrete goal is to generate data structures for elements irrespective of how types were used to describe the data, we need to expand any type reference into element definition where it appears. This is done by expand_element() which will in its turn call expand_complex_type(), expand_group() and expand_attribute_group() to do the job.

3.9.3 Generation Phase

Once %dt is in expanded form, the get_element() is called for each XML namespace. It will generate the code for encoders and decoders for the elements in the XML namespace. Finally the root decoder is gnerated using gen_element(). Furing generation following template files are used

  aux-templ.c      - Code generation template for auxiliary functions
  dec-templ.c      - Code generation template for decoders
  enc-templ.c      - Code generation template for encoders
  getput-templ.c   - Code generation template for accessor functions

A lot of the generated headers are simply hard coded in the (i.e. no templates).

4 Integration with Existing Web Sites

Single Sign-On is used to protect some useful resources. ZXID does not have any means of serving these resources, rather a normal web server or application server should do it (e.g. Apache httpd(8) or Tomcat, or our favorite mini_httpd(8) ). ZXID just concentrates on verifying that a user has a valid session, and if not, establishing the session by way of SSO.

4.1 Brief Overview of Control Flow

The SAML 2.0 specifications mandate a wire protocol, and in order to speak the wire protocol, the SP application typically has to follow certain standard sequence of control flow.

Fig-2: Typical control flow of ZXID SP

First a user ((The user is often referred to as "Principal" in
 more technical jargon. Although the human user and web browser are
 distinct entities, we do not stress that separation here. Whatever
 user "does" really will, in protocol, appear as web browser sending
 requests.)) tries to access a web site that acts in SP role. This triggers following sequence of events

  1. User is redirected to URL in a common domain. This is so that we can read the Common Domain Cookie that indicates which IdP the user uses. Alternatively, if you started at, the CDC check is by-passed and flow 2b. happens.

  2. After the CDC check, a Authentication Request (AuthnReq) is generated. The IdP may have been chosen automatically using CDC (2a), or there may have been some user interface interaction (not show in the diagram) to choose the IdP.

  3. User is redirected to the IdP. The redirection carries as a query string a compressed and encoded form of the SAML 2.0 AuthnReq.

  4. Once the IdP has authenticated the user, or observed that there already is a valid IdP session (perhaps from a cookie), the IdP redirects the user back to the SP.

    The AuthnResponse may be carried in this redirection in a number of alternate ways

    1. The redirect contains a special token called artifact. The artifact is a reference to the AuthnResponse and the SP needs to get the actual AuthnResponse by using a SOAP call (the 4bis step).

    2. The "redirect" is actually a HTML page with a form and little JavaScript that causes the form to be automatically posted to the SP. The AuthnResponse is carried as a form field.

  5. After verifying that AuthnResponse indicated a success, the SP establishes a local session for the user (perhaps setting a cookie to indicate this).

    Depending on how the SP to web site integration is done the user is taken to the web site in one of the two ways

    1. Redirect to the content. This time the session is there, therefore the flow passes directly from check session to the web content.

    2. It is also possible to show the content directly without any intervening redirection.

4.2 Redirect Approach to Integration

*** TBW

4.3 Pass-thru Approach to Integration

4.3.1 mod_auth_saml pass-thru

*** TBW, but see mod_auth_saml.pd for some documentation.

4.3.2 mod_perl pass-thru

*** TBW, but see zxid-perl.pd for some documentation.

4.3.3 PHP pass-thru

*** TBW, but see zxid-php.pd for some documentation.

4.4 Proxy Approach to Integration

*** TBD

5 Testing

You can skip this section if you are not a developer. However, you may be interested, from quality assurance perspective, in the extent of the testing that we perform.

ZXID test suite is driven by and the test input in t/ subdirectory. The test suite is not distributed in the tar ball, but is available from the git repository. Some tests still rely on detailed manual setup, YMMV.

Test coverage of the project is monitored using gcov and lcov tools. This requires ZXID to be compiled in a special way:

  make clean
  make all ENA_PG=1       # Enables -pg flag to gcc, among others

Then you need to start the web servers that are used by the tests, for example:

  mini_httpd -p 8081 -c 'zx*' &

  cd /home/sampo/apache-tomcat-5.5.20/
  killall java; bin/

Now you are ready to run, in the zxid distribution directory, the test suite

  ./ -a -a -dx

The test suite can also be run using web interface: http://localhost:8081/

After running the test suite and possibly performing manual tests, you can generate the test coverage report by running.

  make lcov

You can then view the coverage report by pointing your web browser to lcovhtml/index.html

5.1 Test Suite

The test suite as of release 0.76, January 2011, covers following items:

Test suite 0.76STATUS   SECS  GOAL  TEST NAME                              MESSAGES
OK       0.052 0.1   HELP1 zxcall -h
OK       0.038 0.1   HELP2 zxpasswd -h
OK       0.049 0.1   HELP3 zxcot -h
OK       0.044 0.1   HELP4 zxdecode -h
OK       0.056 0.1   HELP5 zxlogview -h
OK       0.058 0.1   SOENC1 EncDec Status
OK       0.020 0.1   ATORD1 Attribute sorting
OK       0.058 0.1   ATCERT1 Attribute certificate
OK       0.034 0.1   CONF1 zxcall -dc dump config
OK       0.056 0.1   CONF2 zxidhlo o=d dump config
OK       0.021 0.1   CONF3 zxidhlo o=c dump carml
OK       0.027 0.1   CONF4 zxidhlo o=B dump metadata
OK       0.070 0.1   CONF5 zxididp o=B dump metadata
OK       0.100 0.1   META1 Java LEAF Meta
OK       0.023 0.1   HLO1 zxidhlo o=M LECP check
OK       0.020 0.1   HLO2 zxidhlo o=C CDC
OK       0.062 0.1   HLO3 zxidhlo o=E idp select page
OK       0.039 0.1   HLO4 zxidhlo o=L start sso failure
OK       0.043 0.1   HLO5 zxidhlo o=A artifact failure
OK       0.042 0.1   HLO6 zxidhlo o=P POST failure
OK       0.021 0.1   HLO7 zxidhlo o=D deleg invite fail
OK       0.024 0.1   HLO8 zxidhlo o=F not an idp fail
OK       0.021 0.1   IDP1 zxididp o=R fail
OK       0.020 0.1   IDP2 zxididp o=F fail
OK       0.020 0.1   IDP3 zxididp o=N new user fail
OK       0.023 0.1   IDP4 zxididp o=W pwreset fail
OK       0.620 0.1   IDP5 zxididp o=S SASL Req
OK       0.027 0.1   PW1 zxpasswd list user
OK       0.024 0.1   PW2 zxpasswd pw an ok
OK       0.023 0.1   PW3 zxpasswd pw an fail
OK       0.045 0.1   PW4 zxpasswd create user
OK       0.043 0.1   PW5 zxpasswd change pw
OK       0.057 0.1   PW6 zxpasswd list user
OK       0.054 0.1   COT1 zxcot list
OK       0.037 0.1   COT2 zxcot list swap
OK       0.042 0.1   COT3 zxcot list s2
OK       0.083 0.1   COT4 zxcot get idp meta dry
OK       0.046 0.1   COT5 zxcot get sp meta dry
OK       0.023 0.1   COT6 zxcot my meta
OK       0.039 0.1   COT7 zxcot my meta add
OK       0.024 0.1   COT8 zxcot gen epr
OK       0.050 0.1   COT9 zxcot gen epr add
OK       0.022 0.1   COT10 zxcot my meta
OK       0.045 0.1   COT11 zxcot list s2
OK       0.019 0.1   LOG1 zxlogview list
OK       0.063 0.1   LOG2 zxlogview list
OK slow  0.349 0.1   SMIME1 smime key gen ca
OK slow  0.239 0.1   SMIME2 smime key gen joe
Diff ERR 0.025 0.1   SMIME3 smime ca
Diff ERR 0.028 0.1   SMIME4 smime code sig
App Err  0.034 0.1   SMIME5 smime code vfy                  exit=256
Diff ERR 0.034 0.1   SMIME6 smime sig
Diff ERR 0.031 0.1   SMIME7 smime clear sig
OK       0.026 0.1   SMIME8 smime pubenc
App Err  0.044 0.1   SMIME8b smime pubencdec                exit=256
App Err  0.050 0.1   SMIME9 smime sigenc                    exit=256
App Err  0.042 0.1   SMIME10 smime encsig                   exit=256
App Err  0.048 0.1   SMIME11 smime multi sigenc             exit=256
App Err  0.020 0.1   SMIME12 smime query sig                exit=256
App Err  0.020 0.1   SMIME13 smime verify                   exit=256
App Err  0.020 0.1   SMIME14 smime query cert               exit=256
App Err  0.021 0.1   SMIME15 smime verify cert              exit=256
OK       0.016 0.1   SMIME16 smime mime ent
OK       0.015 0.1   SMIME17 smime mime ent b64
Diff ERR 0.029 0.1   SMIME18 smime pkcs12 exp
Diff ERR 0.021 0.1   SMIME19 smime pkcs12 imp
App Err  0.020 0.1   SMIME20 smime query req                exit=256
OK       0.030 0.1   SMIME21 smime covimp
OK       0.071 0.1   SIG1 sig vry shib resp
OK       0.037 0.1   SIG2 sig vry shib post
OK       0.061 0.1   SIG3 sig vry zxid resp
OK       0.056 0.1   SIG4 sig vry zxid post
OK       0.030 0.1   SIG5 sig vry sm resp
OK       0.031 0.1   SIG6 sig vry sm post
App Err  0.030 0.1   SIG7 * sig vry shib resp undecl prefix exit=2816
OK       0.024 0.1   SIG8 * sig vry ping resp
OK       0.026 0.1   SIG9 sig vry ping post
OK       0.040 0.1   SIG10 sig vry hp a7n
OK       0.029 0.1   SIG11 sig vry hp post
OK       0.028 0.1   SIG12 sig vry hp resp
OK       0.028 0.1   SIG13 sig vry hp resp2
OK       0.027 0.1   SIG15 sig vry saml artifact response
OK       0.026 0.1   SIG16 sig vry saml artifact response
OK       0.025 0.1   SIG17 sig vry saml artifact response
App Err  0.041 0.1   SIG18b sig vry prstnt-a7n              exit=2816
OK       0.026 0.1   SIG20b sig vry rsa-a7n
OK       0.024 0.1   SIG21b sig vry rsa-a7n2
OK       0.026 0.1   SIG22b sig vry rsa-idp-post
OK       0.046 0.1   SIG32b sig vry enc-nid-enc-attr
OK       0.031 0.1   SIG37 sig vry
OK       0.022 0.1   SIG38 sig vry
OK       0.023 0.1   SIG39 sig vry
OK       0.034 0.1   SIG40 sig vry
OK       0.025 0.1   SIG41 sig vry
OK       0.187 10    XML1 Decode-Encode SO and WO: ns-bug
OK       0.139 10    XML2 Decode-Encode SO and WO: azrq1
OK       0.164 10    XML3 Decode-Encode SO and WO: azrs1
OK slow  0.014 0.01  XML4 * Decode-Encode RIS malformed 1
OK       0.413 10    XML5 Decode-Encode SO and WO: ana7n1
OK       0.056 10    XML6 Decode-Encode SO and WO: anrq1
OK       0.166 10    XML7 Decode-Encode SO and WO: anrs1
OK       0.327 10    XML8 Decode-Encode SO and WO: dirq1
OK       0.257 10    XML9 Decode-Encode SO and WO: dirs1
OK       0.572 10    XML10 Decode-Encode SO and WO: dirq2
OK       0.223 10    XML11 Decode-Encode SO and WO: dia7n1
OK       0.261 10    XML12 Decode-Encode SO and WO: epr1
OK       0.333 10    XML13 Decode-Encode SO and WO: wsrq1
OK       0.281 10    XML14 Decode-Encode SO and WO: wsrs1
OK       0.577 10    XML15 Decode-Encode SO and WO: wsrq2
OK       0.435 10    XML16 Decode-Encode SO and WO: wsrs2
OK       0.046 10    XML17 Decode-Encode SO and WO: as-req
OK       0.220 10    XML18 Decode-Encode SO and WO: as-resp
OK       0.055 10    XML19 Decode-Encode SO and WO: authnreq
OK       0.017 0.1   XML20 Decode-Encode SO and WO: sun-md
OK       0.019 0.1   XML21 Decode-Encode SO and WO: provisio
OK       0.045 0.1   XML22 Decode-Encode SO and WO: provisio
OK       0.041 0.1   XML23 Decode-Encode SO and WO: pds-crea
OK       0.021 0.1   XML24 Decode-Encode SO and WO: pds-quer
OK       0.032 0.1   XML25 Decode-Encode SO and WO: AdvCliennt
OK       0.029 0.1   XML26 Decode-Encode SO and WO: AdvClient
OK       0.021 0.1   XML27 Decode-Encode SO and WO: AdvClient
OK       0.033 0.1   XML28 Decode-Encode SO and WO: AdvClien
OK       0.018 0.1   XML29 Decode-Encode SO and WO: AdvClien
OK       0.019 0.1   XML30 Decode-Encode SO and WO: zx a7n
OK       0.014 0.1   XML31 Decode-Encode SO and WO: covimp
OK       2.736 30    ZXC-AS1 Authentication Service call: SS
OK slow  1.069 0.1   ZXC-AS2 Authentication Service call: An
OK       5.019 30    ZXC-IM1 Identity Mapping Service call
OK       5.059 30    ZXC-IM2 * SAML NID Map call
OK       7.840 30    ZXC-IM3 SSOS call
OK       1.667 30    ZXC-DI1 Discovery Service call
OK slow  2.024 0.03  ZXC-DI2 List EPR cache
OK       9.880 30    ZXC-WS1 AS + WSF call: idhrxml
OK       16.51 30    ZXC-WS2 AS + WSF call: x-foobar
OK slow  9.338 0.1   ZXC-WS3 AS + WSF call leaf (x-recurs)
OK slow  2.879 0.1   ZXC-WS4 AS + WSF call EPR not found
OK slow  1.086 0.1   ZXC-WS5 AS + WSF call bad pw
OK slow  9.408 0.1   ZXC-WS6 AS + WSF call hr-xml bad
OK slow  9.677 0.1   ZXC-WS7 AS + WSF call hr-xml create
OK slow  9.855 0.1   ZXC-WS8 AS + WSF call hr-xml query
OK slow  9.787 0.1   ZXC-WS9 AS + WSF call hr-xml mod
OK slow  9.697 0.1   ZXC-WS10 AS + WSF call hr-xml mod
OK       0.116 0.5   LOGIN-IDP1 IdP Login screen            len=1933
OK       0.219 0.5   LOGIN-IDP2 IdP Give password           len=685
OK       0.121 0.5   LOGIN-IDP3 IdP Local Logout            len=2309
OK       0.120 0.5   SSOHLO1 IdP selection screen           len=3280
OK       0.441 0.5   SSOHLO2 Selected IdP                   len=2649
App Err  0.115 0.5   SSOHLO3 Login to IdP
OK       0.120 0.5   SSOHLO4 POST to SP                     len=3280
OK slow  0.674 0.5   SSOHLO5 SP SOAP Az                     len=52742
OK       0.113 0.5   SSOHLO6 SP SOAP defed                  len=3280
OK       0.109 0.5   SSOHLO7 SP SOAP defed                  len=3280
OK       0.110 0.5   SSOHLO8 SP SOAP logout                 len=3280
OK       0.110 0.5   SSOHLO9 SP local logout                len=3280
OK       3.010 10    COVIMP1 Silly tests, to improve cov    len=3280
=== Test success 135/155 (87.1%) ===

As can be seen from the output, the smime tool has still many unresolved problems. Other test failures are explained in the comments in the application. Major part of that application is a large table of tests where the test setup is described and any anomalies are commented on.

Fig-3: Test output using web interface.

5.2 Test Coverage

The test coverage report looks as follows

Fig-4: Test coverage report.

As of R0.73, December 2010, the test coverage was about 63% of the handwritten lines of code that could execute. While this figure is still mediocre, it should be noted that 100% test coverage is inachievable and useless stretch goal. We feel about 80% would be good.

There are several reasons why 100% is not achievable:

  1. Defensive coding requires us to insert error checks at many layers. This means that some of the error checks will never trigger because the checks in other layers already checked the situation. It is therefore virutally impossible to construct a test case that would cause the code path to be taken.

  2. Similar to above, some checks require extreme inputs, e.g. to overflow buffers. Such inputs may be very expensive to generate and extremely unlikely in real practise. While these situations should be tested for security vulnearabilities, there is not much harm done if null pointer exception causes a cgi process to crash rather than return meaningful error message. The cost of testing these corner cases can be hard to justify.

  3. We have peppered the code with extensive debug prints. While crash due to debug print is nasty, it is also avoidable by turning off the debug flag. Not worth burning too much midnight oil to concot test cases to test every corner case in this area.

  4. The test coverage considerations do not include subdirectory c/ as that contains machine generated code. This is highly repetitive and there is no point to include it in coverage score.

With the above caveats, it still needs to be admitted that more testing could be done. In particular the biggest gaps appear in areas where new functionality is already supported at encoder-decoder level, but not yet realized in hand written logic.

6 License

Copyright (c) 2006-2009 Symlabs (, All Rights Reserved. Author: Sampo Kellomäki (

Copyright (c) 2011 Sampo Kellomäki (, All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

While the source distribution of ZXID does not contain SSLeay or OpenSSL code, if you use this code you will use OpenSSL library. Please give Eric Young and OpenSSL team credit (as required by their licenses).

Binary distribution of this product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit ( See LICENSE.openssl for further information.

Binary distribution of this product includes cryptographic software written by Eric Young ( Binary distribution of this product includes software written by Tim Hudson ( See LICENSE.ssleay for further information.

And remember, you, and nobody else but you, are responsible for auditing ZXID and OpenSSL library for security problems, back-doors, and general suitability for your application.

6.1 Dependency Library Licenses

ZXID strives to maintain IPR hygiene and avoid both non-free and GPL license contamination. All the dependency libraries have BSD style licenses

Please see each library package for the exact details of their licenses.

6.2 Specification IPR

ZXID is based on open SAML and Liberty specifications. The parties that have developed these specifications, including Symlabs, have made Royalty Free (RF) licensing commitment. Please ask OASIS and Liberty Alliance for the specifics of their IPR policies and IPR disclosures.

Some protocols, such as WS-Trust and WS-Federation enjoy Microsoft's pledge ((If you have a reference to where this pledge can be
 found, please let me know so it can be included here.)) that they will not sue you even if you implement these specifications. You should evaluate yourself whether this is good enough for your situation.

6.3 Further Warranties

If you need the author or Symlabs to further disclaim IPR interest or make warranties of non-infringement, such declarations are available for a fee. Please contact

Legal queries and clarifications will be answered at then-current Symlabs Professional Services rate, please contact


7.1 Compilation Problems

7.1.1 OpenSSL not found: you need to create

ZXID does NOT have a configure script. It ships with a notion of "standard" locations for the three dependency libraries, but if these libraries are not where it expects to find them, then typically you see (n.b. lines were folded for presentation):

  If you get compilation errors, try: make help
  gcc -g -fpic -fmessage-length=0 -Wno-unused-label -Wno-unknown-pragmas
     -fno-strict-aliasing -D_REENTRANT -DDEBUG -DUSE_CURL -DUSE_OPENSSL
     -DLINUX -I/tmp/zxid-0.20 -I/usr/local/ssl/include -I/usr/local/include
     -c -o zxid.o zxid.c
  zxid.c:34:23: curl/curl.h: No such file or directory
  In file included from zxid.c:38:
  zx.h:26:25: openssl/rsa.h: No such file or directory

What happened is that OpenSSL for some reason is not in the location where standard OpenSSL distribution would install it (as indicated by -I/usr/local/ssl/include flag that ships with ZXID Makefile). You need to determine where OpenSSL is installed in your case. You can use

  find / -name rsa.h -ls

to locate candidates.

For example, if it turns out that OpenSSL is installed in /opt/ssl, then you need to create a file that indicates this location:

  echo OPENSSL_ROOT=/opt/ssl >

There are several other make variables you may need to tweak. In the above example, we also notice that libcurl was not found where expected. This would be fixed like this

  echo CURL_ROOT=/opt/curl >>

Net result? ZXID does not try to guess where the libraries are. It makes you do the foot work of locating the correct libraries (some people have more than one instance installed) and prepare the This may seem like a lot of work, but in my experience, fixing GNU autohell configure scripts that guess wrong is thousand times more frustrating. The system is dumb by design so you, as a human, do not have to try to second guess it - you are in control.

7.1.2 Missing gperf

  gcc -g -fpic -fmessage-length=0 -Wno-unused-label -Wno-unknown-pragmas -fno-strict-aliasing -D_REENTRANT -DDEBUG -DUSE_CURL -DUSE_OPENSSL -DLINUX -I/c/cvs/zxid_cvs -I/usr/local/ssl/include -I/usr//include   -c -o c/zx-a-aux.o c/zx-a-aux.c
  c/zx-a-aux.c: In function "zx_NEW_a_Action":
  c/zx-a-aux.c:80: error: "zx_a_Action_ELEM" undeclared (first use in this function)

This happens because c/zx-const.h was misgenerated (it should not happen at all if you do not supply ENA_GEN=1) and does not include the necessary defines. c/zx-const.h should have more than 1900 lines and look something like

  /* generated file, do not edit! zx_ _ATTR */
  #ifndef _zx__ATTR
  #define _zx__ATTR
  #define zx_use_ATTR     0
  #define zx_used_ATTR    1
  #define zx_sequence_ATTR        2
  #define zx_wantDSEPR_ATTR       347
  #define zx_ZX_TOK_NOT_FOUND_ATTR        348
  #define zx__ATTR_MAX    349
  /* generated file, do not edit! zx_ _ELEM */
  #ifndef _zx__ELEM
  #define _zx__ELEM
  #define zx_ds_Y_ELEM    0
  #define zx_gl_Y_ELEM    1
  #define zx_gl_esrd_ELEM 2
  #define zx_wst_OnBehalfOf_ELEM  1629
  #define zx_ZX_TOK_NOT_FOUND_ELEM        1630
  #define zx__ELEM_MAX    1631

7.1.3 make samlmod gives "incompatible types in assignment"

Should not happen with version 0.21 or later. See zxidnoswig.h for explanation of the problem.

7.1.4 Perl compiled with different compiler than zxid

Perl modules generally want to be compiled with the same C compiler and options as were used to compile perl itself (see perl -V). If this happens to be different than the compiler you have defined in CC variable (gcc by default, near top of Makefile or in, you may get an error like:

  cd Net; perl Makefile.PL && make
  Warning: -L.. changed to -L/home/sampo/zxid/Net/..
  Writing Makefile for Net::SAML
  make[1]: Entering directory `/home/sampo/zxid/Net'
  cc -c  -I.. -I/apps/openssl/std/include -I/apps/include -D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBUGGING -fno-strict-aliasing -pipe -Wdeclaration-after-statement -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -O2 -march=i586 -mtune=i686 -fmessage-length=0 -Wall -D_FORTIFY_SOURCE=2 -g -Wall -pipe   -DVERSION=\"\" -DXS_VERSION=\"\" -fPIC "-I/usr/lib/perl5/5.8.8/i586-linux-thread-multi/CORE"   SAML_wrap.c
  /bin/sh: cc: command not found
  make[1]: *** [SAML_wrap.o] Error 127
  make[1]: Leaving directory `/zxid/Net'
  make: *** [samlmod] Error 2


  1. Compile zxid with compiler that was used for perl, e.g.

         make CC=the-compiler-that-perl-wants
  2. Recompile perl using the compiler that you want to use for zxid

  3. Tinker with PATH environment variable so that both C compilers are found. However, using two different compilers is not really supported.

In general these types of problems happen when you use perl installed by your distribution, but have later compiled a gcc of your own. It may even be that you never installed the distribution cc - in that case consider installing it and then trying approaches 1 or 3.

A similar situation can arise with incompatibility of the compiler and options used for dependency libraries, such as OpenSSL or libcurl, and those used for compiling zxid itself.

7.1.5 All files under zx missing

You need to symlink zx to zxid source directory, thus

  ln -s . zx

If you do not have it, then you will get a lot of file inclusion errors for headers that are supposed to be in path starting by zx/

The symlink is there to keep all hand written source files on top level of directory for ease of development, yet allow inclusions to go through zx subdirectory. When zxid is installed, it goes to /usr/include/zx. Hence the symlink keeps the includes the same whether developing or using installed version.

7.1.6 Compiler Warnings

If you compile zxid with compiler warnings turned on (CFLAGS += -Wall), you will see quite a number of warnings, most of which are unwarranted. Since the warnings are unwarranted, I ship zxid Makefile with warnings turned off. If this bothers you, feel free to investigate the warnings and report to me any issues you uncover.

Following warnings in partuclar are unwarranted:

  1. Any unusued variable warnings, especially in generated code. Most common of these is se variable (see enc-templ.c).

  2. "Suggest parenthesis around assignment when used as truth value." I rely on C language operator precedence. Also, in most cases the assignment is the only expression in the truth test - there simply is no opportunity for ambiguity -- and no justified case for gcc to warn about this.

  3. "Suggest parenthesis around && when used in ||". I rely on C language operator precedence, hence the suggestion is redundant.

Some warnings you may want to worry about

  1. "int format, long int arg". On 32 bit platforms int and long are both 32 bits so this warning is not an issue. On 64 bit platforms, however, there may be cause for worry.

7.1.7 SWIG and Java Problems

javac -J-Xmx128m -g zxidjava/*.java zxidjava/ cannot find symbol symbol : class SWIGTYPE_p_p_void location: class zxidjava.zxidjni

  public static zx_str zx_rsa_pub_enc(zx_ctx c, zx_str plain, SWIGTYPE_p_p_void rsa_pkey, int pad) {

zxidjava/ cannot find symbol symbol : class SWIGTYPE_p_p_void location: class zxidjava.zxidjni

  public static zx_str zx_rsa_pub_dec(zx_ctx c, zx_str ciphered, SWIGTYPE_p_p_void rsa_pkey, int pad) {

zxidjava/ cannot find symbol symbol : class SWIGTYPE_p_p_void location: class zxidjava.zxidjni

  public static zx_str zx_rsa_priv_dec(zx_ctx c, zx_str ciphered, SWIGTYPE_p_p_void rsa_pkey, int pad) {

zxidjava/ cannot find symbol symbol : class SWIGTYPE_p_p_void location: class zxidjava.zxidjni

  public static zx_str zx_rsa_priv_enc(zx_ctx c, zx_str plain, SWIGTYPE_p_p_void rsa_pkey, int pad) {

This was due to missing SWIG generated classes. Probably interrupted file transfer.

javac -J-Xmx128m -g zxidjava/*.java cannot find symbol symbol : method new_conf(java.lang.String) location: class zxidjava.zxidjni

      cf = zxidjni.new_conf("/var/zxid/");
                  ^ cannot find symbol symbol : method url_set(zxidjava.zxid_conf,java.lang.String) location: class zxidjava.zxidjni

      zxidjni.url_set(cf, url);
             ^ cannot find symbol

jar cf zxidjava.jar .class jar cf /tmp/zxidjava.jar zxidjava/.class

javac -J-Xmx128m -g cannot access zxid_conf bad class file: /Library/Java/Extensions/zxidjava.jar(zxid_conf.class) class file contains wrong class: zxidjava.zxid_conf Please remove or make sure it appears in the correct subdirectory of the classpath.

  public static int mgmt_screen(zxid_conf cf, zxid_cgi cgi, zxid_ses ses, char op)

1 error

Underscore in linking error

./ Start... Exception in thread "main" java.lang.NoSuchMethodError: zxidjava.zxidjni.new_conf(Ljava/lang/String;)Lzxidjava/zxid_conf;

        at zxid.main(

This was due to finding some old copies from system paths.

java -classpath .:zxidjava -Djava.library.path=zxidjava zxid Start... Exception in thread "main" java.lang.UnsatisfiedLinkError: _zxid_new_conf

        at zxidjava.zxidjniJNI._zxid_new_conf(Native Method)
        at zxidjava.zxidjni.new_conf(
        at zxid.main(

7.2 Platform Specifics

If your Unix platform is not mentioned, you should try saying just


which will compile with Linux options. These options actually are pretty close to pure POSIX compile so you should get very close to working configuration.

7.2.1 Linux

Native development platform. Just say


Seems there are some "improvements" that distributions have made. ZXID adopts the policy of expecting dependency modules where the module author meant it to be installed by default - for example OpenSSL by default installs in /usr/local/ssl (naming is historic, but has stuck). Many distros tinker with these paths. This means you need to create a

Redhat used to have an issue with Net::SAML (make samlmod). This has since been fixed, please see zxidnoswig.h for explanation.

No doubt, distros will eventually pick up ZXID and provide it as a package. Once that happens they will solve any path issues accoring to their disto policy and that is fine, just do not ask me to comply with any such policy.

7.2.2 FreeBSD

No target available on Makefile, but a port is available from

7.2.3 Solaris (Sparc)

  make TARGET=sol8
  make TARGET=xsol8    # Cross compile for Solaris (e.g. on Linux host)

7.2.4 MacOS X (PowerPC?)

  make TARGET=macosx

7.2.5 Windows Using MinGW

  make zxid.dll TARGET=xmingw    # Cross compile on Linux host (best supported)
  make zxid.dll TARGET=mingw     # Native compile for mingw target in Cygwin environment

Eitherway, the net result is native Windows DLL that does not have Cygwin library dependencies or GPL encumberation.

See Makefile for further mingw notes.

7.2.6 Windows Using Cygwin

  make TARGET=cygwin

Very experimental (as of Oct 2007) native build for Cygwin.

Cygwin appears to not have neither flock(2) nor lockf(2). This is strange because at least one of these is implemented on MinGW. Current workaround is to define flock() to be empty macro. This of course means there is no file locking. There are 3 known races where things can go wrong

  1. Audit logs can get garbled. This does not stop ZXID from working, but may make log analysis more complicated.

  2. Auto-CoT metadata writes can get garbled. This is very unprobable, but if it happens, the ZXID deployment will not work towards affected IdP. Nothing to worry about really.

  3. Locking is used to protect against updates of zxid.conf while zxid is running. Again any corruption is very unlikely. Nothing to worry about.

The results of Cygwin compile may be GPL encumbered due to libraries.

7.2.7 Windows Using MSVC

Never been done (as of Oct 2007), but probably this is not very difficult given that MinGW port already has addressed many Windows platform issues. Please send any success reports, and receipes, my way.

7.3 Deployment Planning

Here is a rudimentary decision tree for deployment planning

  1. List your applications

    1. Any provided by external partner?

    2. Non web apps

  2. Document your existing identity stores and approaches to

    1. User provisioning (when someone is employed)

    2. Application provisioning (when someone starts using app)

    3. Authorization: how do you know who is supposed to be doing what?

    4. Deprovisioning: what happens when someone is fired?

    5. Login? Per app? Harmonized user names? Enterprise SSO?

  3. Document your goal: federated SAML SSO über alles :-)

    1. Do you want to run IdP?

    2. Could you out-source IdP?

    3. Will your partners / customers be running their own IdPs?

    4. Will you participate (or run) single CoT or do you need to consider cross CoT inter-operation (e.g. IdP proxying)

To be continued...

8 Support

8.1 Mailing list and forums

Mail the author until we get the list set up. Or volunteer a list :-)

8.2 Bugs

Mail the author until we get bug tracking set up. Or volunteer.

8.3 Developer access

We use CVS, but access needs to be manually configured and is not anonymous. If you contribute significantly, I will bother. Others can send patches (good way to show you are worthy of CVS access) to me. I've heard some mixed experiences about open source sites like sourceforge. If you run such site and want to host ZXID Project, please contact me.

If you just always want the latest source: get the tar ball from the downloads section. Trust me, this is still so much in flux that only the tar ball snapshots are in any usable state. CVS access just to get latest source would be pointless.

8.4 Commercial Support

Following companies provide consultancy and support contracts for ZXID:


SAML 1.1 Core, OASIS, 2003
"Bindings and Profiles for the OASIS Security Assertion Markup Language (SAML) V1.1", Oasis Standard, 2.9.2003, oasis-sstc-saml-bindings-1.1
Peted Davis, Ed., "Liberty Metadata Description and Discovery Specification", version 1.1, Liberty Alliance Project, 2004. (liberty-metadata-v1.1.pdf)
Conor Cahill et al.: "Liberty Alliance Web Services Framework: A Technical Overview", Liberty Alliance, 2008. File: idwsf-intro-v1.0.pdf (from\_center/papers)
Jonathan Tourzan and Yuzo Koga, eds.: "Liberty ID-WSF Web Services Framework Overview", Liberty Alliance, 2006. liberty-idwsf-overview-v2.0.pdf from\_center/specifications
"Assertions and Protocols for the OASIS Security Assertion Markup Language (SAML) V2.0", Oasis Standard, 15.3.2005, saml-core-2.0-os
"Profiles for the OASIS Security Assertion Markup Language (SAML) V2.0", Oasis Standard, 15.3.2005, saml-profiles-2.0-os
"Bindings for the OASIS Security Assertion Markup Language (SAML) V2.0", Oasis Standard, 15.3.2005, saml-bindings-2.0-os
"Authentication Context for the OASIS Security Assertion Markup Language (SAML) V2.0", Oasis Standard, 15.3.2005, saml-authn-context-2.0-os
Cantor, Moreh, Phipott, Maler, eds., "Metadata for the OASIS Security Assertion Markup Language (SAML) V2.0", Oasis Standard, 15.3.2005, saml-metadata-2.0-os
"Security and Privacy Considerations for the OASIS Security Assertion Markup Language (SAML) V2.0", Oasis Standard, 15.3.2005, saml-sec-consider-2.0-os
"Conformance Requirements for the OASIS Security Assertion Markup Language (SAML) V2.0", Oasis Standard, 15.3.2005, saml-conformance-2.0-os
Eric Tiffany, ed.: "SAML 2.0 Interoperability Testing Procedures, Version 2.0", Liberty Alliance, 7 July 2006. File: Liberty-SAMLv2.0-TestPlan-v2.0-Final.pdf
"Test Plan for Liberty Alliance SAML Test Event, Test Criteria SAML 2.0 Version 3.0 Errata F", Drummon Group Inc, 2007. File: Liberty\_DGI\_4Q07\_Interoperability\_SAML\_Test\_Criteria\_Test\_Plan\_vs.3.0.Errata.F.pdf
"Glossary for the OASIS Security Assertion Markup Language (SAML) V2.0", Oasis Standard, 15.3.2005, saml-glossary-2.0-os
XML Canonicalization (non-exclusive),; J. Boyer: "Canonical XML Version 1.0", W3C Recommendation, 15.3.2001,, RFC3076
Exclusive XML Canonicalization,
Dick Hardt and Yaron Goland: "Simple Web Token (SWT)", Version, Microsoft, Nov. 4, 2009 (SWT-v0.9.5.1.pdf)
Allen Tom, et al.: "OAuth Web Resource Authorization Profiles (OAuth WRAP)", Version, Google, Microsoft, and Yahoo, Nov. 5, 2009 (WRAP-v0.9.7.2.pdf)
"XML Encryption Syntax and Processing", W3C Recommendation, 10.12.2002,
"XML-Signature Syntax and Processing", W3C Recommendation, 12.2.2002,, RFC3275
Cahill, ed.: "Liberty ID-WSF Discovery service 2.0", liberty-idwsf-disco-svc-2.0-errata-v1.0.pdf from\_center/
Liberty ID-WSF Discovery service 1.2 (liberty-idwsf-disco-svc-v1.2.pdf)
"Liberty ID-WSF People Service Specification", liberty-idwsf-people-service-1.0-errata-v1.0.pdf from\_center/specifications/
"Liberty ID-WSF 2.0 Security Mechanisms", liberty-idwsf-security-mechanisms-core-2.0-errata-v1.0.pdf from\_center/specifications
"Liberty ID-WSF Authentication, Single Sign-On, and Identity Mapping Services Specification", liberty-idwsf-authn-svc-2.0-errata-v1.0.pdf from\_center/specifications/
"Liberty ID-WSF SOAP Binding Specification", liberty-idwsf-soap-binding-2.0-errata-v1.0.pdf from\_center/specifications
Sampo Kellomäki and Jukka Kainulainen, eds.: "Liberty Data Services Template 2.1", Liberty Alliance, 2007. liberty-idwsf-dst-v2.1.pdf from\_center/specifications/
Sampo Kellomäki and Jukka Kainulainen, eds.: "Liberty DST v2.0", Liberty Alliance, 2006.
Liberty DST v1.1
Sampo Kellomäki, ed.: "Liberty Identity based Directory Access Protocol", Liberty Alliance, 2007.
Sampo Kellomäki, ed.: "Liberty Personal Profile specification", Liberty Alliance, 2003.
Liberty ID-WSF Interaction Service protocol 1.1
Liberty ID Federation Framework 1.2, Protocols and Schemas
Liberty Subscriptions and Notifications specification
Henry S. Thompson et al. (eds): XML Schema Part 1: Structures, 2nd Ed., WSC Recommendation, 28. Oct. 2004,
P. Deutcsh, J-L. Gailly: "ZLIB Compressed Data Format Specification version 3.3", Aladdin Enterprises, Info-ZIP, May 1996
P. Deutcsh: "DEFLATE Compressed Data Format Specification version 1.3", Aladdin Enterprises, May 1996
P. Deutcsh: "GZIP file format specification version 4.3", Aladdin Enterprises, May 1996
S. Josefsson, ed.: "The Base16, Base32, and Base64 Data Encodings", July 2003. (Section 4 describes Safebase64)
Microsoft Web Browser Federated Sign-On Protocol Specification, 20080207,