Securing a Server's Logon
Passwords are weak. Originally, usernames and passwords were stored on servers. That approach was vulnerable if someone got hold of the list. So, a shadow file system was set up to make it harder to get to the real list. But that was still too weak. Instead of storing passwords, the hashes of the passwords were stored. However, dictionary attacks and rainbow tables made this technique also vulnerable. Next, salted hashes (concatenating a random number before a password was hashed) were tried, but the salt itself had to be available for the computer to use to verify the password. In this case, very fast computers could do dictionary attacks against a salted list of passwords. So the server started doing many iterations of a hash—hashing the hash of the hash of the password, perhaps 1,000 times—to try to make dictionary attacks more expensive while not doing so many hashes that verifying a password took too long. Then cloud computing came along, making even this defense insufficient.
The TPM can be used to solve this problem. Instead of having the salt in the clear, a keyed hash can be used with the key stored in the TPM. The HMAC is over the user ID and password. If this is done, then even if the entire list of HMACed passwords were published, it wouldn't do an attacker any good—not having the key, they would have to rely on the TPM to do the HMACing. This reduces the risk of parallelization attacks or offline attacks using very fast computers.
Implementing this is relatively easy. In Linux, authentication is done using pluggable authentication modules (PAMs); they're designed specifically to allow different forms of authentication to be added to Linux.
First a large random number is created—say, a 256-bit number—which you use as your HMAC key. This is created with the TPM2_GetRandom command of the TPM or the Tpm2_GetRandom function in the FAPI. These commands ask how many bytes you want: in this case, you ask for 32 bytes. You call this result M and store it in a safe in case your TPM ever dies or the motherboard is replaced.
Next you need to load M into the TPM. You can do this with the TPM2_Load command.
You choose an empty buffer password for M, because you want to use it without authorization. (You want to store M persistently, so you can't use the TPM2_LoadExternal command.) You load it into the storage hierarchy using the owner authorization.
Then you use TPM2_EvictControl to make M persist in the TPM. This call also gives it a persistent handle, which can thereafter be used to identify M in the TPM.
Now you need to write a PAM (which is outside the scope of this book). When given a new password, it uses the TPM2_HMAC command to HMAC the user ID and password with M. When a user ID and password are passed in for authorization, the PAM likewise
HMACs them with M and then compares the result with what is in the user ID / HMAC list.
The HMAC command is relatively fast, so this shouldn't delay the authentication procedure significantly, but it should be a good defense against attacks that steal the password file and try to reverse-engineer it with offline attacks of any sort.
Locking Firmware in an Embedded System, but Allowing for Upgrades
Healthcare systems need to be secure. Unfortunately, there has been a lot of research showing that devices such as pacemakers and glucose-control systems aren't terribly secure. One way of making a system more secure is to be certain the firmware used to run the device is approved by the manufacturer. This means a public key has to be available to the device, to verify that the firmware that is being loaded has been correctly signed by the manufacturer. But where can you store the key?
The obvious solution is to store the key in the TPM. This public key can be loaded using the TPM2_LoadExternal command and then made persistent using the TPM2_EvictControl command. Now commands that are used to update the firmware can use the certified TPM2_VerifySignature command to verify that the new firmware is indeed signed by the manufacturer before it's loaded. Writing cryptographic code isn't easy to do without making mistakes, so having certified code to do the cryptographic calculations is a real advantage.
As a side note, a similar approach could be used for documents: passports or even currency could come with signatures. A portable scanner with a TPM in it could have public keys preloaded that match the authority that made the documents and could be quickly used to verify the signature. If a counterfeiter started producing large numbers of fake bills, they would first require a large number of real bills from which to copy the signatures. If they copied only a few bills, once found, those certificates could be easily revoked.
TPM 2.0 is more than just a collection of algorithms that can be performed in hardware. It's an enabler of new functionality. The examples in this chapter haven't (to our knowledge) been attempted in commercial or open source software yet, but we're excited to see that happen. Even if only the solution for strengthening the storage of passwords were implemented, it would be a big win for the community. Security problems are everywhere, and TPM 2.0 can be used as a tool to provide solutions for those problems.