Cryptosense PKCS#11 Compliance Testing: Opencryptoki

Graham Steel
February 4, 2015

Update March 2018

Since we wrote this post our compliance criteria have been extended to over 100 covering PKCS#11 v2.40 and used to find a host of issues with live HSMs.

Original post:

Recently we've been trying out our PKCS#11 compliance tester on a number of open-source PKCS#11 implementations. We'll be publishing the results here over the next few weeks, as well as sending the reports from our tools to the project developers. First up: Opencryptoki and its PKCS#11 software token.We ran our smart-fuzzing tool on Opencryptoki in its "base strategy" mode, designed to offer a good compromise between analysis time and precision of results. This involves executing about 250,000 PKCS#11 command calls, which takes about 30 seconds on a 3406MHz Linux box. Afterwards, it takes about a minute to run the results past 63 of our compliance criteria.

The top line of the report shows for 5 of our compliance criteria, at least one test failed. Clicking on the table we can see in more detail what the failures were.

Tracing the cause

Let's go through the first failure in detail. It concerns the property "CKA_ALWAYS_SENSITIVE is false on keys made by C_CreateObject", and we can see the reference to where this is specified in v2.20 of the standard (Section 11,7 on page 128 of the PDF version). Out of 2292 calls, 233 failed. We sent our results to one of our clients who we knew were interested in Opencryptoki (they also have an interesting PKCS#11 proxy project). And in reply, they sent us the following code snippet from the Opencryptoki:

source:usr/lib/pkcs11/common/object.c (line 403)
...
// for key objects, we need be careful
...
// note: I would think that keys loaded with C_CreateObject should
// have their CKA_NEVER_EXTRACTABLE == FALSE and
// CKA_ALWAYS_SENSITIVE == FALSE since the key data was presumably
// stored in the clear prior to the call to C_CreateObject. The
// PKCS #11 spec doesn't impose this restriction however.
//
if (class == CKO_PRIVATE_KEY || class == CKO_SECRET_KEY) {
rc = template_attribute_find( o->template, CKA_SENSITIVE, &attr );
if (rc == FALSE) {
OCK_LOG_ERR(ERR_FUNCTION_FAILED);
rc = CKR_FUNCTION_FAILED;
goto error;
}
flag = *(CK_BBOOL *)attr->pValue;
rc = build_attribute( CKA_ALWAYS_SENSITIVE, &flag, sizeof(CK_BYTE), &sensitive );
...

The comments are a great example of how tricky it is to implement a 407-page spec like PKCS#11. In fact, following the reference from the Cryptosense report to page 128 of the spec, we find:

"If C_CreateObject is used to create a key object, the key object will have its CKA_LOCAL attribute set to CK_FALSE. If that key object is a secret or private key then the new key will have the CKA_ALWAYS_SENSITIVE attribute set to CK_FALSE, and the CKA_NEVER_EXTRACTABLE attribute set to CK_FALSE." 

So, contrary to the comments in the code, the standard does specify the intuitively correct behaviour, though it is rather hidden.

Deeper bugs

To aid in diagnosing more complex bugs, our compliance tester can output exactly the test cases that highlighted the failures. The tool also allows you to replay these test cases to evaluate patches.

Over the next few weeks, we'll be giving example reports on a number of other open-source projects. If you would like your project included, or if you would like to test a demo version of the tool on your proprietary implementation, get in touch.