System Administration

Parsing the EU Digital COVID Certificate

I recently go my first Covid-19 shot, and shortly after that I received my QR code that is supposed to prove to anybody that I’m vaccinated.

Of course, I was interested in the actual technical implementation of the thing so I started tinkering around. Initially, I wasn’t sure whether the QR code just links to a webpage or is a standalone document, but reading the documentation quickly made clear that it simply contains a signed document.

There is a python snippet floating around that does all the decoding (decode base45, decompress, decode cbor, ignore signature, cbor decode), but I was wondering whether I can just use standard Linux command-line tools to do the same.

To my big surprise, I could not find a simple base45 decoder to be used on the command line. Neither the GNU coreutils (which supports a bunch of encodings) or basez have implemented base45 yet. For a quick coding exercise, getting code into the coreutils was a bit too ambitious, so I rolled my own in a few minutes. I haven’t done coding in C for quite some time, so this was fun. (while probably not necessary, this should be doable as a one-liner in Perl)

Next step: The libz decompression. Here, too, I was surprised that my Debian box did not have a simple program ready to do it. After some googling, I found that
zlib-flate -uncompress
does the trick. zlib-flate is included in the qpdf package.

Update: The debian package zlib1g-dev contains a few example programs, zpipe.c does exactly what I need. Just copy the file from /usr/share/doc/zlib1g-dev/examples/ , compile with “cc -o zpipe zpipe.c -lz”.

Then cbor: at first this looked easy, there is a libcbor0 in Debian and appropriate modules for Perl and Python. But a command-line tool? That’s not included by default.

Initially, I tried using
python3 -m cbor2.tool
and then continue with jq to select the right element (jq ‘.”CBORTag:18″[2]’ seems to do the trick) but I ran into encoding issues: I did not manage to extract the element in binary form, I always had escape sequences like ‘\x04’ or ‘\u0012’ in there which are not suitable for next step of cbor decoding.

Update: I’ve now read a bit more about the cbor standard and on the things it can do that JSON can’t, is handling raw binary data. JSON knows strings, yes, but they are character strings encoded in utf-8, not sequences of octets. Back in the old days of latin1 that might not have mattered that much, but these days you really shouldn’t mix those two.

So this is still work in progress, watch this space for updates.


  • I’m not the only one who tried this, see also this blogpost by┬áCorentin Dupont.
  • Based on troubles with faked certificates, I had a closer look at the key distribtion and updates of the Austrian green pass system. I documented the results in a blogpost at

System Administration

Testing …

Is this thing still on?

My old wordpress installation has been suffering from bit-rot and the upgrade to Debian jessie completely killed the wordpress installation. I’m moving over posts and pages manually, let’s see if I get this blog (including pictures) up and running again.



System Administration

Moving …

The disks in my old root server are finally both failing, so I’m moving all my stuff to a new machine.

As usual in IT, you get a lot more power for the same money now, and so I’m quite pleased with the performance of the new server. I’ve tried to do a more secure and cleaner setup this time and distribute the service over domUs in a XEN setup. We’ll see how that works out in real life.

One thing is different this time: I can’t take my old, free /29 with me to the new server. Additional IP-addresses cost extra money now, and I’m not prepared to pay extra for them. Instead, I’ve got a block of IPv6 addresses and will run anything that I can’t DNAT/proxy via v6.

I moved email service over two weeks ago, yesterday evening this blog. If something is not working as expected, tell me.

System Administration

Linux, iostat and device names

My favorite tools for looking at the I/O load of Linux boxes are iotop and iostat. Running “iostat -xm 5” is one of the first things I do whenever I have the feeling that a server might be I/O-bound. The output is perfectly fine and useful on your typical one-disk box, but once you throw in either Xen or DM-Crypt, then the output is not so intuitive any more as it is no longer clear what each of the dm-XX devices is actually holding.

So I whipped up the following quick perl script to translate them:

#!/usr/bin/perl -w
# Replace dm-x names in stdin with names from /dev/mapper, e.g.
# iostat -xm 5 | $0
# Otmar Lendl, 2012/08/24

use strict;

my %m;

foreach my $l (split(/\n/, `ls -l /dev/mapper`)) {
# lrwxrwxrwx 1 root root      8 May  3 18:49 vg1-abusehelper--swap -> ../dm-21
        if ($l =~ /\d\d:\d\d ([\w-]+) -> \.\.\/(dm-\d+)/) {
                $m{$2} = $1;

while(<>) {
        s/(dm-\d+)( *) /substr($m{$1}. (' ' x 80),0,length($1.$2)).' '/eg;

The quotes in substitution line should be plain single quotes, not the typographic nonsense that wordpress insists on inserting.

Share and Enjoy!

System Administration

Nokia 2680s and iSync

Now that Andrea owns a Mac again it was overdue to get iSync up and running with her Phone.

iSync is nice, but her Nokia 2680 is neither supported by the 10.7 iSync, nor does Nokia provide a suitable plugin. Luckily, there are alternatives. Paul Bain has published a few plugins on his blog, including one for the 3600 Slide. According to one of the comments, that should be pretty easy to adapt for the 2680s.

Installing the plugin and replacing all occurrences of “3600 Slide” with “2680s” was simple, but it didn’t work: iSync still complained about an “unsupported phone”.

The solution became apparent when looking at the log in /var/log: the phone is actually a “2680s-2”, and once I got the strings right, iSync was happy.

To make things easier for others trying to replicate this, here is a zip of the my resulting plugin. (And I hope plain zip did the job, and I’m not running into some macos resource fork & co weirdness.)


System Administration

Offline plugin for DokuWiki

I’ve been trying to adapt the offline plugin to our needs. Here are my changes:



  • It clashes with how “datadir” is set in the example in the security page. That field must not contain a trailing ‘/’.
  • The plugin should remove the .zip file before adding files to it to avoid obsolete files accumulating there.
System Administration

RFC 5105, Client Toolkit and Xerces 3

I recently got a request for help concerning the generation of ENUM Validation Tokens according to RFC 5105.

In order to check what went wrong, I had to re-install the software I used while writing that RFC. That wasn’t so easy as the upgrade from Xerces 2 to Xerces 3 made a few changes to the XML Signing module necessary:

System Administration

mod_epp 1.7 released

I’ve just uploaded mod_epp 1.7 to

Thanks to CentralNIC for funding the debugging effort.

(And no, there will no picture of me with a brown paper bag over my head on this blog. But yes, that bug was stupid.)

System Administration

A lesson in software licenses

Just a quick remark: a “aptitude install ddd” showed that this package depended on lesstif2 which is an Open Source re-implementation of the Motif GUI library.

Most of the reader here will never have heard about Motif.

Back when I started working with X, there were two competing GUI standards: OpenLook and Motif. Free Software (the term Open Source wasn’t invented yet) stuck to the basic Athena Widgets or (later) used Tk. Despite the strict licensing scheme of Motif some projects (e.g. the original Mosaic Browser) went with Motif nevertheless — motivating the Lesstif project.

It could have owned the Unix GUI market, but it wasn’t compatible with free software, so it lost the battle for developer mindshare and fell into obscurity. Qt almost made the same mistake, but they were a bit more liberal in the beginning and as GTK took off, they had to open up even more to stay relevant.

In other words, the decision not to support free software with Motif killed it.

System Administration

Dear Cisco

I’m doing a bit of network monitoring with SNMP again, and stumbled upon yet another cisco SNMP bug. Back when I wrote the pan-european NMS for KPNQwest, I had to work-around a good number of bugs in the IOS snmp agent, but this time it’s a bug in the MIB file:

Using the CISCO-BGP4-MIB, I can graph the state of my BGP peerings. All fine, when looking at

    CbgpPeerAddrFamilyPrefixEntry ::= SEQUENCE {
        cbgpPeerAcceptedPrefixes        Counter32,
        cbgpPeerDeniedPrefixes          Gauge32,
        cbgpPeerPrefixAdminLimit        Unsigned32,
        cbgpPeerPrefixThreshold         Unsigned32,
        cbgpPeerPrefixClearThreshold    Unsigned32,
        cbgpPeerAdvertisedPrefixes      Gauge32,
        cbgpPeerSuppressedPrefixes      Gauge32,
        cbgpPeerWithdrawnPrefixes       Gauge32

you notice that the Gauge32 vs. Counter32 types are mixed up.

cbgpPeerAcceptedPrefixes is the only Gauge here, whereas cbgpPeerDeniedPrefixes, cbgpPeerAdvertisedPrefixes, cbgpPeerSuppressedPrefixes and cbgpPeerWithdrawnPrefixes are actually Counters, e.g.

    cbgpPeerWithdrawnPrefixes  OBJECT-TYPE
        SYNTAX      Gauge32
        MAX-ACCESS  read-only
        STATUS      current
                "This counter is incremented when a route prefix,
                 which belongs to an address family, is withdrawn on
                 this connection. It is initialized to zero when the
                 connection is undergone a hard reset."
        ::= { cbgpPeerAddrFamilyPrefixEntry 8 }