blob: 7b0505592f44f3256e54a0236d0ad1c76c9d3b89 [file] [log] [blame]
Testing PKCS11 on a development box
===================================
It's quite useful to be able to unit test and debug actual PKCS11 calls on
your dev machine. It saves the time of fumbling with the little netbook and
makes iteration much faster.
Our typical z600's don't have a hardware TPM, but that's actually not a problem.
It turns out it's much easier to unit test with a software TPM, since they
never require hard reboots to clear the TPM.
So, if you get to the point where you want to hack on pkcs11 calls on your
dev box, this document can help you get a working software TPM.
Install "TPM Emulator"
----------------------
TPM Emulator requires cmake, which wasn't installed on my machine. In addition,
the version of it that apt-get wanted to install was too old. I downloaded
the latest binary tarball from <http://www.cmake.org/cmake/resources/
software.html> and expanded it on my local disk. I ran cmake using an
absolute path to the binary. You might want to properly install it in your
path somewhere, but I was in a rush.
TPM Emulator also requires GMP, from <http://gmplib.org/>. This installed (on
the host, outside of the chroot) without a hitch. Just remember to build it
on the local disk so you can install it when it's done*.
Finally, TPM Emulator comes with a kernel module, and needs your kernel
headers to compile it. In my case `sudo apt-get install
linux-headers-2.6.24-gg804006` did the trick. You are almost definitely
running a different version of the kernel. Check it with `uname -a`, find the
appropriate headers package, and install it.
Once you've got the requirements installed, download the latest tarball from
<http://tpm-emulator.berlios.de/>. Build it on your machine, outside of the
chroot. Make sure to build it on the local disk, so you can
`sudo make install` when it's done*. The TPM Emulator page has build
instructions. In my case it went like:
$ cd ~/local/src/tpm-emulator/
$ mkdir build
$ cd build
$ ~/local/cmake/bin/cmake ../
$ make install
Once you've got that build, insert the kernel module. The module doesn't seem
to get installed as part of `make install`, so you need to install it from the
build directory...
$ cd ~/local/src/tpm-emulator/
$ sudo insmod build/tmpd_dev/linux/tmpd_dev.ko
This kernel module appears to be a small redirector that sends requests from
/dev/tpm over to the Unix domain socket that the emulator will actually listen
to. You can verify that it was properly installed with...
$ lsmod | grep tpmd_dev
And remove it with...
$ rmmod tpmd_dev
But you don't want to remove it right now. Instead, continue on by starting
up the emulator. First, make a directory for the emulator to stash its
working state. The default location for the tpm emulator state clashes with
trousers, so you'll want to pick a new location. I used...
$ mkdir ~/local/var/tpm/
Then, start up the daemon...
$ sudo tpmd -f -d -s ~/local/var/tpm/
The -f argument tells it to run in the foreground, so you can easily stop it
with Ctrl-C if you want. The -d argument makes it print extra debugging info.
*Note: On Google workstations, root can't access your NFS home directory. If
you're not using a Google workstation, or don't have an NFS mounted home
directory, this probably doesn't apply to you.
Setup TrouSerS
--------------
Install TrouSerS if you don't already have it, using...
$ sudo apt-get install trousers
TrouSerS is an API over raw /dev/tpm access, so that applications can code to a
higher level of abstraction. Start it on your host (outside of the chroot)
with...
$ sudo tcsd -f
Now you can try actually poking at your tpm. Trousers comes with a set of
tpm utilities in /usr/sbin, though you don't actually need root to run them.
Start off with an easy one...
$ /usr/sbin/tpm_version
TPM Version: 01010000
Manufacturer Info: 4554485a
Then...
$ /usr/sbin/tpm_getpubek
Public Endorsement Key:
... lots of stuff...
If that all works, try taking ownership of the TPM...
$ /usr/sbin/tpm_takeownership
Enter 111111 (six ones) for both the owner and the Storage Root Key (SRK)
passwords. Now clear the SRK password...
$ /usr/sbin/tmp_changeownerauth -s
Enter owner password:
Enter new SRK password:
Confirm password:
Enter 111111 for the owner password, then leave the SRK password blank (just
press ENTER.) After this, check to be sure you actually have ownership, try
something like...
$ /usr/sbin/tpm_setclearable -s
Enter owner password:
Owner Clear Disabled: false
Force Clear Disabled: false
The -s means 'status', which will just print whether or not the TPM can be
cleared. If you get "Authentication failed", something is bad and you've got
to fix it.
If it works, then it's time to try in the chroot, read on.
The /dev/ tree in chroot is linked to /dev on your host. You should be able
to verify that /dev/tpm is the same in both places by running `ls -i /dev/tpm/`
in and out of the chroot. It should return the same inode number both times.
Now enter your chroot and try tpm_setclearable again. This time though,
you're going to have to run the binary that was built for the target, using
something like...
chroot$ scripts/run_32bit.sh /build/x86-generic/usr/sbin/tpm_setclearable -s
The run_32bit.sh shell script just modifies your library path so that the
32 bit libraries come first, so that you can run things that were built for
the 32 bit image.
The tpm_setclearable command should work exactly the same as it did outside of
the chroot. If so, go get a coffee, a smoke, or go for a run around the block.
You're getting close.
PKCS#11, OpenCryptoki, and You
------------------------------
PKCS#11 defines an API for talking to cryptographic smart cards, or "tokens".
These tokens are hardware that can perform cryptographic operations. They are
used for things like...
* Generating a secure keypair on the hardware, without revealing the
private portion of the key. Both the public and private key reside
in some form of NVRAM on the token, but the token may only reveal the
public key.
* Perform on-chip encryption or decryption using the keypair.
* Storing arbitrary application data on-chip in public or password
protected NVRAM.
The API assumes that your machine has one or more slots, which can each
contain a token. Not all tokens support all operations, and the API has
a way to query the token to find out what it supports.
OpenCryptoki is an implementation of the PKCS#11 API specification. It can
be used to talk to real hardware tokens, but it also comes with a software
based token that uses the TPM to encrypt an on-disk database of the token's
NVRAM. This software based token is what the Enterprise Daemon uses to
store VPN and 802.1x certificates.
Setup OpenCryptoki
------------------
From here on out, we'll be working in the chroot. We have a particular version
of openCryptoki in there, and it's sometimes a finicky piece of software to
work with.
Before you get started, make sure you've built a recent tree, and that it works.
It's helpful to know that whatever you've got built in the chroot is sane, so
go ahead and build an image and boot it on a device.
Then, from inside the chroot, add yourself to the pkcs11 group. Something
like...
chroot$ sudo /usr/sbin/usermod -a -G pkcs11 $USER
( The pkcs11 group should be made as part of the build. If you don't have it )
( try exiting the chroot and re-entering. )
Then exit the chroot and come back in, to make sure it took affect. Prove it
to yourself with something like...
chroot$ groups | grep pkcs11
Now you'll need to create the virtual slot with the TPM based virtual token...
chroot$ cd ~/trunk/src/scripts
chroot$ sudo ./run32_bit.sh /build/x86-generic/usr/sbin/pkcs_slot -- 0 tpm
( A lot of the commands in this part require the run32_bit.sh script. You )
( can save yourself some typing by running `./run32_bit.sh bash`, so that )
( the environment variable changes live for the life of the new bash shell. )
( When you're done, press Ctrl-D to return back to the previous )
( environment. )
The pkcs_slot script from OpenCryptoki is written in Bash, you can peek
inside if you're curious what it really does.
The pkcsslotd program expects to be run from /usr/sbin, but in the chroot
it is built into /build/x86-generic/usr/sbin. A symlink will fix that...
chroot$ cd /usr/sbin/
chroot$ sudo ln -s /build/x86-generic/usr/sbin/pkcsslotd .
Now start pkcsslotd with...
chroot$ cd ~/trunk/src/scripts
chroot$ sudo run_32bit.sh /usr/sbin/pkcsslotd
This should start without issue, and you can move on to some quick tests...
chroot$ ./run_32bit.sh /build/x86-generic/usr/sbin/pkcsconf -- -i
PKCS#11 Info
...
chroot$ ./run_32bit.sh /build/x86-generic/usr/sbin/pkcsconf -- -s
Slot #0 Info
...
chroot$ ./run_32bit.sh /build/x86-generic/usr/sbin/pkcsconf -- -t
Token #0 Info:
...
Flags: 0x880045 (RNG|LOGIN_REQUIRED|CLOCK_ON_TOKEN|USER_PIN_TO_BE_CHANGED|
SO_PIN_TO_BE_CHANGED)
...
Notice the flags associated with the token. The fact that it is missing
TOKEN_INITIALIZED means that the token hasn't yet been set up. Also notice
USER_PIN_TO_BE_CHANGED and SO_PIN_TO_BE_CHANGED, which mean that our token
these PINs (numeric passwords) to be changed. Tpmtoken_init helps with that...
chroot$ ./run_32bit.sh /build/x86-generic/usr/bin/tpmtoken_init
A new TPM security officer password is needed. The password must be between
6 and 127 characters in length.
Enter new password:
Type 111111 (six ones) and press enter. When this completes the tokens
flags should be different...
chroot$ ./run_32bit.sh /build/x86-generic/usr/sbin/pkcsconf -- -t
Token #0 Info:
...
Flags: 0x44D (RNG|LOGIN_REQUIRED|USER_PIN_INITIALIZED|CLOCK_ON_TOKEN|
TOKEN_INITIALIZED)
...
Now we have TOKEN_INITIALIZED, and the PINs no longer need to be changed.
Now list out all of the object stored on the token...
$ ./run_32bit.sh /build/x86-generic/usr/bin/tpmtoken_objects
Enter your TPM user password:
No objects found
And there you go! We haven't put anything on the token yet, so there is
nothing to list. You're now ready to unit tests that require a functioning
PKCS#11 device, without having to copy them to the netbook, or reboot to
clear your TPM.
Troubleshooting
---------------
Don't forget to remove the SRK password as described above. If you do forget,
you'll get a 0x6 error (CKR_FUNCTION_FAILED) when you try to initialize the
token.
If you're getting 0x2 (CKR_HOST_MEMORY) errors, you probably aren't in the
pkcs11 group, or pkcsslotd hasn't started.
The openCryptoki website is absolutely awful. It's basically a blank page that
looks like it should have some information in it, but doesn't. There is
a little documentation in the source though. Start with the FAQ:
<http://opencryptoki.git.sourceforge.net/git/gitweb.cgi?p=opencryptoki/
opencryptoki;a=blob_plain;f=FAQ;hb=HEAD>.
For more information on the PKCS#11 API see the RSA website <http://www.rsa.com/
rsalabs/node.asp?id=2133>. Specifically, the PKCS#11 Core Specification, which
is not as daunting as it looks at first.
For a little more nitty gritty, open /build/x86-generic/usr/include/
opencryptoki/pkcs11types.h in your editor. This can be a handy way to map
hexadecimal error codes to their mnemonics when things go wrong.
If you get sideways and want to start from scratch, here are the things you
might want to remove (it's probably a good idea to stop the daemons that might
have open file handles before removing this stuff):
* Outside of the chroot, tpmd is going to store some state wherever you told
it to with the -s option. This document recommended ~/local/var/tpm.
* Also outside of the chroot, the TrouSerS daemon tcsd stores some state in
/var/lib/tpm/.
* Inside the chroot, pkcsslotd stores your token data under
/var/lib/opencryptoki/...
- The pk_config_data file is a manifest of slots, created by pkcs_slot.
- The tpm/ directory contains per-user NVRAM for the TPM backed slot. If
you're going to delete this, make sure the entire user directory goes
away. The pkcs_slot script won't correctly repopulate the directory if
it finds some leftovers from a previous run.