Attacks on Key-Wrapping in PKCS#11 v2.40

Graham Steel
June 22, 2016

In the standard API for HSMs and other cryptographic hardware, PKCS#11, key-wrapping refers to the process of encrypting one key stored in hardware with another in order to send the first key somewhere else in a secure way. This operation has been the source of a whole series of security vulnerabilities, in particular because the encryption modes are often vulnerable to padding oracle attacks.

In PKCS#11 v2.40, new authenticated encryption modes were introduced. Properly implemented, these modes are secure against padding oracle attacks. This is good news, but unfortunately AES-GCM and AES-CCM, the two new modes, introduce a new security problem.

The two-time pad

Both AES-GCM and AES-CCM are what is known as counter modes. That means the encryption part of their operation works by using the AES block cipher to calculate a keystream that will be XORed against the plaintext. Roughly speaking, the first block of the keystream is obtained  by encrypting an initialisation vector (IV). The second block of the stream is obtained by increasing the IV by 1 and encrypting again. This is repeated until the keystream is as long as the plaintext. Such modes have several advantages: the security proof for the confidentiality part is quite direct, and encryption and decryption can be parallelized easily. However, in PKCS#11, the IV is supplied as a parameter by the calling application. That means there is nothing to stop a compromised application controlled by an attacker from using the same IV twice.

This opens up a whole series of attacks. For example, suppose the attacker wants to obtain the value of a wrapped secret key s. Suppose the ciphertext c containing the encryption of s was obtained at a certain HSM by calling the PKCS#11 command C_WrapKey using either CCM or GCM mode, and suppose the attacker obtains access to the HSM. The attack works even if we assume k is safely stored inside the HSM and properly protected by its permission attributes, i.e. not extractable, and the key s is no longer even present on this HSM.To obtain s, the attacker can first store a known key in the HSM, using the C_CreateObject command that imports a cleartext value as a key.

For simplicity, suppose he imports a string of 0s as the key. Then he asks the HSM to encrypt the string of 0s with the key k using C_WrapKey, and gives the same IV as was used in the ciphertext c, obtaining c'. Finally he XORs c and c' to obtain the plaintext value of s. Why does this work? Because if ks is the keystream generated by the IV and the key k, then c XOR c' is equal to ks XOR s XOR ks XOR 0. If you XOR any x with 0 you get x, and if you XOR any x with itself you get 0. So ks XOR s XOR ks XOR 0 = s XOR ks XOR ks = s.

This isn't the first time we've seen this problem: the YubiHSM has exactly the same issue. Even if the attacker can't use C_CreateObject (for example if it is disabled on this HSM), there are many other ways to import a known key onto an HSM, including taking advantage of padding oracle attacks on insecure unwrap modes, or incorrectly set permissions that allow encryption as well as unwrapping.

The fix

The solution is to force the HSM itself to generate the IVs for wrapping keys under CCM or GCM, and to make sure the wrapping keys can't be used for any other functions using the existing permission attributes.

Here at Cryptosense we're working in a proposal for key wrapping for PKCS#11 v3.0 that will include this and other features to allows keys to be wrapped along with their attributes, to avoid another family of attacks where keys are unwrapped with different permissions from when they were wrapped. We'll keep you updated with news of that here, though you can also follow discussions on the PKCS#11 TC site (and the mailing list is public).

Meanwhile, to find out more about PKCS#11 security, start with our whitepaper.