Thursday, August 26, 2010

Key Wrapping with HSMs

Using PKCS11 with JCE means that you can use HSMs to house your private keys, which protects them from theft or misappropriation. And that's a very good thing.

With JCE, you use instances of subclasses of Key to perform cryptographic operations. Keys can be PublicKey, PrivateKey or SecretKey objects. SecretKey objects represent keys to use with a symmetric algorithm, like AES. PublicKey and PrivateKey objects comprise a key pair used for asymmetric algorithms, like RSA.

What PKCS11 does is replace SecretKey and PrivateKey objects with sham objects that represent index numbers into the HSM. When you ask JCE to perform a cryptographic operation with those keys, it instead actually delegates the task to the HSM. The HSM will look up the keys, use them internally, and return the result to you. When done that way, the secret material never leaves the HSM.

But what happens when you have to manage potentially thousands of keys? That's too many to store in the limited storage space of an HSM, and having the HSM root through its storage to find the key you want isn't what it was designed best to do.

No, instead you should use a database to store all of the keys. But the problem is that the database isn't cryptographically protected the same way an HSM is.

The solution is in the Cipher class wrap() and unwrap() methods.

What you do is you establish a SecretKey in your HSM. Give it an alias of "WrappingKey" or something of that sort. If you ask your HSM to generate such a key internally, then it will never be allowed to leave the HSM. That's a good thing. You then generate whatever keys you need and use the Cipher wrap() method to turn the private key material into an encrypted byte array. You can write that byte array to the database with confidence, since there's no use you can make of that byte array without the secret key that was used to encrypt it, which is safely encased in the HSM.

Now what if you want to use it?

You fetch the bytes from the database again and use the same Cipher object to unwrap the key. What you'll get is a PrivateKey. But as we've seen, PrivateKeys that you get from an HSM are just sham objects. You don't actually get to see that PrivateKey - it is merely a reference to the key in the HSM. You then can use the HSM to perform whatever crypto operation you need to do on that key. The HSM doesn't permanently store the unwrapped key - as soon as the sham object gets dereferenced, the PKCS11 module will tell the HSM to throw it away. But done in this way, the unencrypted form of the private key never leaves the HSM, nor does the encryption key that wraps and unwraps it. Your database can be used to keep track of the potentially millions of private keys you need to keep track of, but no human eyes will ever get to see even one of them.

2 comments:

Anonymous said...

I realize this is an old blog entry, but I'm posting this comment because I was planning to follow this advice until I did further research on the subject.

Unfortunately, there appears to be a number of vulnerabilities when using PKCS#11 in this manner. PKCS#11 specifies a series of security mechanisms based on key attributes that dictate how keys can be used, whether they can be exported (i.e., wrapped) from the HSM, and whether they can be revealed (in plaintext) outside the HSM. For example, you can generate a key with CKA_SENSITIVE set to TRUE but CKA_EXTRACTABLE set to FALSE. This allows the key to be wrapped and stored in the outside database in an encrypted form but not directly revealed in plaintext outside the HSM (which is a good thing). Unfortunately, wrapping a key exports only the key material itself from the HSM, without any of the accompanying attributes. When the key is unwrapped (re-imported) into the HSM, a new set of attributes must be specified. An attacker with access to user-level HSM credentials can unwrap the key but set CKA_SENSITIVE to FALSE and then proceed to reveal the key in plaintext by calling C_GetAttributeValue on the CKA_VALUE attribute of the newly unwrapped key. Therefore, wrapping keys off the HSM effectively bypasses all of the HSM's protection mechanisms.

It appears that the latest proposal for PCKS#11 v2.40 addresses these shortcomings: see https://cryptosense.com/algorithm-choice-in-pkcs11-part-2-changes-to-rsa-in-v2-40/

"...there is one very interesting feature in this mechanism which is that for the first time, it allows a standardized mechanism for key wrap to carry information about the attributes that the unwrapped key should be given. These attribute values are given via the PKCS#8 private key structure. The problem of managing attributes under wrap and unwrap gives rise to a whole host of attacks... and often leads to vendor lock-in as proprietary mechanisms have to be used."

Hopefully others will find this information useful as well.

Nick said...

That is all true in the abstract, but in the concrete implementation of PKCS11 on an HSM (from Utimaco), there are restrictions on the templates that you're allowed to use for unwrapping keys. In this particular instance, it's impossible to unwrap a key and have it not be sensitive.

Of course, it's up to the implementation to add restrictions like this, as there's nothing in the spec that would otherwise prevent it.