Understanding the DNIe, Part I : Device Authentication
For a long time I wanted to have the opportunity to analyze the Spanish electronic ID, known in Spain as the DNIe. Last Christmas I was finally able to get an appointment with the appropriate police station in Spain and could get my brand new DNIe. Over a few posts I'm going to tell you how I've been trying to understand what the device does without access to any confidential information whatsoever, using information freely available on the Internet and analyzing communication logs between my PC and my DNIe.
The DNIe is a smart card implementing an E-SIGN application. This application is specified by the CWA-14890 documents (where CWA means CEN Workshop Agreement, and CEN means European Committee for Standardization ) and provides an interoperable framework for secure signature devices.
These devices are designed to be used for electronic signatures, and in the Spanish case it has replaced the identity document we have used for many years. It is an ISO 7816 compliant smart card, with (afaik) a custom operating system. The IC has received an EAL5+ Common Criteria certificate issued by the French scheme, while the ICC has been certified by the Spanish scheme and has obtained EAL4+.
This is all public documentation you can find on the Internet:
- EAL5+ CC certificate for the ST19WL34A issued by Serma Technologies in 2005.
- EAL4+ CC certificate for the DNIe OS issued by the CCN.
- ESIGN specifications: CWA14890-1 and CWA14890-2.
These documents show the Common Criteria certificates for the chip and the card, and the specifications of the protocol followed by the card.
Further, the Spanish Administration provides an OpenSC library in binary form, that one can use for communicating with the cards in Linux an Mac OS X. They also provide a CSP for Microsoft Windows. In the remainder of this post I'll explain my attempts at understanding how the device and the protocol work.
Everything has been done with consumer equipment on an Ubuntu 9.10 computer and using public documentation, thus everyone holding an actual DNIe should be able to reproduce these steps. Let's try to understand the details about this thing and how it communicates with our PC. We will start with the Device Authentication phase, which is the first thing that takes place when you use your eID.
Let me remind once again that I do not have access to any confidential information related to the DNIe, and therefore this is all public information. Also, I've done this analysis on my own free time sitting at home and using publicly available tools and a PCSC reader obtained from Tractis.
First things first, we need to install the drivers. To that end I followed the procedure described by the Spanish Administration in www.dnielectronico.es. Once it was working, I authenticated myself against a test website they provide at https://av-dnie.cert.fnmt.es/compruebacert/compruebacert.
The authentication process worked fine, and I was shown some information about myself taken from the digital certificate stored on the card. However, the signature test did not work and it just said "Your browser could not generate a valid signature".
Since it always annoys me when I don't know why things fail, I dove into the HTML code and saw the JavaScript they use to ask for a signature. I added a print statement to see the actual error, but it was a very concise "error: internalError" message. So my next step was to enable APDU logging in PCSCD (using the -a option ) and take a look at the communication triggered by the use of the pkcs11-tool from OpenSC.
Another way for doing it is setting the OPENSC_DEBUG environment variable to 9 and using the OpenSC log to get the APDUs. Yet another way would be using the pkcs11-spy module, but I didn't really try this one.
A quick smart card (iso7816 APDU) reminder
As you might know, part of my work involves evaluating smart card security. Therefore I'm quite familiar with the ISO7816 APDU structure and related stuff. However, it might well be that some readers never read a word about APDUs before. Let's make a fast summary with a few facts:
- Smart cards and terminals communicate through APDUs. The terminal requests an action from the card with an APDU request and the card gives a response.
- APDU requests include the following: CLA INS P1 P2 Lc <Data> <Le>. CLA and INS are identifiers of the action you request to the card. P1 and P2 are parameters, Lc is the length of the provided data and Le is the length of the expected response.
- APDU responses include the following: <Data> SW1 SW2. SW1 and SW2 form the so called status word, which gives information on whether the command succeeded or not and why.
Wow! This was fast. You can get more info from Wikipedia, or if you speak Spanish you can take a look at my former Smart card series of posts.
DNIe: Initial communication analysis
Ok, my next step was trying to determine why the signing process did not work. Is it something in my Firefox? Something in the binary driver? The card is not behaving in a correct way?
Of course to get an answer I first need to understand how the communication works. So my first attempt at it is to try to sign something using the command line tool pkcs11-tool and look at the communication. I'll try to find the PIN I enter in the log to start with...
However, this approach is fundamentally flawed. It assumes that the PIN is sent somehow in plaintext, which is actually not the case. After not understanding anything from the communication at a first glance, I decide to actually look at the specs (see link to CWA14890-1 at the beginning of this post).
It turns out the card and the terminal (PC) establish a secure channel before any further communication is performed, and therefore you are not able to see any plaintext information in the log.
Device authentication
Let's summarize what happens during the establishment of this secure/trusted channel. After receiving the Answer To Reset (ATR) from the card, the terminal sends the following APDU:
> 90 B8 00 00 11
At this point, I don't know what this command means. However, I have sent this command several times to the card and verified that the response is static. Also, it doesn't seem very important to me right now, and I'm more interested on what comes next.
UPDATE 12/04/2010: Over the weekend I have implemented the authentication protocol explained in this post and found out that this APDU returns the serial number of the card. It's important because it is used in the INTERNAL AUTHENTICATE explained below. One should use the 7 first bytes of the response as the serial number, padding them with a leading 00 byte.
After this, the device authentication process actually starts. This process is described in CWA 14980-1, but I'm going to show how it looks like here. First, the terminal (IFD from now on) issues a SELECT command to select the Master File:
> 00 A4 04 00 0B 4D 61 73 74 65 72 2E 46 69 6C 65
< 61 1B > 00 C0 00 00 1B
< 6F 19 84 0B 4D 61 73 74 65 72 2E 46 69 6C 65 85 0A 38 3F 00 00 0B FF FF FF FF FF 90 00
The above means that the terminal selects the master file by its name (Master.File) and the card responds 61 1B, which means ok, I have 1B bytes of response ready for you. Then the IFD issues a GET RESPONSE command requesting the card to send those 1B bytes.
Now, what happens next is that the card selects another file by its ID (60 1F), which turns out to contain the card certificate for the authentication process:
> 00 A4 00 00 02 60 1F
< 61 0E > 00 C0 00 00 0E
< 6F 0C 85 0A 01 60 1F 03 25 00 FF FF FF FF 90 00
This response shows that the file contains 0x325 bytes of information. The IFD reads them using the READ BINARY ISO7816 command in several chunks:
> 00 B0 00 00 F0
< 30 82 03 ... 90 00 > 00 B0 00 F0 F0
< 09 2A 86 ... 90 00 > 00 B0 01 E0 F0
< 97 94 B8 ... 90 00 > 00 B0 02 D0 55
< 2E FE C0 ... 90 00
At this point, the terminal knows the public key of the card and can verify it using the PKI set up by the Spanish authorities. Following this process, the IFD sends a couple of certificates with its own public key and the CA public key in CV (Card Verifiable) form , so that the card can verify them:
> 00 22 81 B6 04 < 4 bytes ID >
< 90 00 > 00 2A 00 AE D2 < certificate1 >
< 90 00 > 00 22 81 B6 0A < 10 bytes ID >
< 90 00 > 00 2A 00 AE D1 < certificate2 >
< 90 00
And now the card also knows the public key of the other end. They are ready to engage in an authentication process now. First the IFD sets the parameters of the authentication process, which includes identifying the keys to be used for authentication and providing the IFD serial number:
> 00 22 C1 A4 12 84 < key ID > 83 0C 00 00 00 00 < IFD Serial number >
< 90 00
And then it sends an INTERNAL AUTHENTICATE command. This commands sends a challenge to the card and the IFD serial number sent before. Then, the card will produce a digital signature over these and other values and encrypt it under the IFD's public key provided earlier in the process.
> 00 88 00 00 10 < 8 byte challenge > < IFD Serial Number >
< 61 80 > 00 0C 00 00 80
< encrypted digital signature
Inside this encrypted digital signature, the card has placed it's own 32 byte random number as well as the information provided by the IFD. The inclusion of the challenge ensures that the session is fresh and no replay is taking place. The random number sent by the card is later used to generate session keys.
At this point, the IFD can verify that the card is a valid one. This is done by verifying the digital signature received and comparing the random numbers (nonces) sent and received. If both verifications succeed, the session is fresh and the other end knows the card's private key. Therefore, assuming the card is secure enough to keep the private key private, the IFD has certainty that it's talking to a valid card.
The next step in the protocol is to authenticate the IFD itself. So far the card has proved it's validity, but the IFD has not. This is the purpose of the EXTERNAL AUTHENTICATE command. Similarly to the previous command, now the IFD sends a 32 byte random value which will be used for session key generation.
However, to assure the freshness of this command, the IFD has to request a challenge from the card and include it in the signature. So, the commands that follow now are a GET CHALLENGE command and an EXTERNAL AUTHENTICATE command:
> 00 84 00 00 08
< < 8 byte challenge > 90 00
> 00 82 00 00 80 < encrypted digital signature >
< 90 00
And now we're done. Before sending this 90 00 response, the card has verified the digital signature from the external authenticate command and compared the nonce with the one it replied to the last get challenge command.
In addition, they share two 32 byte random values, one generated by each end. These two values are only known to them, since they have been encrypted with the other end's public key, and have also been authenticated using digital signatures.
Session key generation
After the process described above, the two ends share some secret values and are able to generate shared session keys for subsequent operations.
What they do in this case, is XORing the two 32 byte values ( and
respectively) to generate a shared value which is influenced in the same way by both parties. This ensures that no party has complete control over the key (and actually, as long as one of them is random, the result is also random).
Now, this value is concatenated with a constant (1) and hashed with the SHA-1 algorithm to produce what the specifications name HASH1. The same thing is done with a second constant (2) to produce HASH2.
The initial 16 bytes of each of this hashes is used as a 3DES key for the subsequent secure messaging commands. The first one is used as an encryption key and the second one is used as an authentication key (using MACs).
Future posts
This is it for this article. In the future, I want to try to reproduce this steps on my own using some scripting language and try to request a digital signature from my card.
Therefore, you can expect explanations on how secure messaging works and how a digital signature is requested to the card. This includes how to perform a card holder verification using the PIN code.
Hope you are enjoying it. Feedback is more than welcome!
March 2nd, 2010 - 10:47
So, if I understood it right: the IFD has his own public key?
And, another doubt: the IFD is the computer trying to access the card, or is it the reader device?
March 4th, 2010 - 19:24
@Alvaro yes, that’s right. The IFD has its own 1024 bit RSA key pair, with a card verifiable certificate signed by the CA of the DNIe.
AFAICT both linux and OS X versions of the drivers use the same certificate, which leads me to believe that ALL computers will use the same public/private key pair.
So it’s not very useful as an authentication mechanism actually…and I initially thought it would not be useful for protecting the privacy and integrity of the secure channel but now I think it actually is unless you hook the RNG of the driver and are able to discover the 32 byte random number the IFD picks.
I’d have to look more into it, but my current feeling is that eavesdropping a communication requires both knowing the private key and the random number sent by the IFD, while establishing a secure channel of your own only requires knowing the private key :roll:.
And yes, the IFD is the computer in this case… it’s what the card sees “on the other end”, the logical entity that talks to the card using the iso7816 and the CWA 14980 protocols.
Hence, it’s the combination of reader+computer, since the reader implements the lower layers of the iso7816 stack (physical layer and link layer [T=0, T=1…] ) and the computer implements the upper layers.
March 6th, 2010 - 01:35
Great post! I can’t wait for further posts about DNIe and its implementation.
I hope this comment it’s not caught again by Akismet’s jaws
March 7th, 2010 - 23:38
Seems to be pretty secure… I think.
Great article, can’t wait for next one.
March 21st, 2010 - 12:23
Thanks for the article.
I’m trying to use DNIe for starting session (Gnome, KDE, ssh, …)
Any suggestion about how to do it? I’ve found some documentation, but up to now, it has no worked.
I use opensuse 11.2 and Kubuntu 9.04.
Thanks
November 19th, 2010 - 10:58
Which are the certificate1 and certificate2 sent to the memory of the card, please?
I cannot see the bigger picture.
Nice work. I’m going slowly throug all the steps, in Cocoa.
Thanks