Skip to content

Conversation

minego
Copy link

@minego minego commented Jun 23, 2025

This is a 2nd attempt, because the last rebase in my previous pull request (#200) broke the logic and I missed it. This corrects that oversight.

The PKCS#11 specification states

The constant CK_UNAVAILABLE_INFORMATION is used in the ulValueLen field to denote an invalid or unavailable value. See C_GetAttributeValue for further details.

This MR exposes the CK_UNAVAILABLE_INFORMATION constant definition (along with CK_EFFECTIVELY_INFINITE which is defined next to it, for completeness sake) and checks for that result after calling C_GetAttributeValue

This corrects a crash when a PKCS#11 module returns this. I believe this will fix the following issues:
#139
#60

Prior to this change the returned value was being interpreted as an actual size, which resulted in attempting to allocate an array of size -1 which causes an overflow:

  File "pkcs11/_pkcs11.pyx", line 726, in pkcs11._pkcs11.Object.__getitem__
  File "pkcs11/_utils.pyx", line 11, in pkcs11._pkcs11.CK_BYTE_buffer
  File "stringsource", line 152, in View.MemoryView.array.__cinit__
OverflowError: Python int too large to convert to C ssize_t

Copy link
Collaborator

@MatthiasValvekens MatthiasValvekens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, I rebased your changes, but the tests fail. Looking into the reasons why, it has to do with some library functions not coping well with these None responses.

Copying the relevant text of the spec below: https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/csd01/pkcs11-spec-v3.1-csd01.html#_Toc98177195


  1. If the specified attribute (i.e., the attribute specified by the type field) for the object cannot be revealed because the object is sensitive or unextractable, then the ulValueLen field in that triple is modified to hold the value CK_UNAVAILABLE_INFORMATION.

  2. Otherwise, if the specified value for the object is invalid (the object does not possess such an attribute), then the ulValueLen field in that triple is modified to hold the value CK_UNAVAILABLE_INFORMATION.

  3. Otherwise, if the pValue field has the value NULL_PTR, then the ulValueLen field is modified to hold the exact length of the specified attribute for the object.

  4. Otherwise, if the length specified in ulValueLen is large enough to hold the value of the specified attribute for the object, then that attribute is copied into the buffer located at pValue, and the ulValueLen field is modified to hold the exact length of the attribute.

  5. Otherwise, the ulValueLen field is modified to hold the value CK_UNAVAILABLE_INFORMATION.

If case 1 applies to any of the requested attributes, then the call should return the value CKR_ATTRIBUTE_SENSITIVE. If case 2 applies to any of the requested attributes, then the call should return the value CKR_ATTRIBUTE_TYPE_INVALID. If case 5 applies to any of the requested attributes, then the call should return the value CKR_BUFFER_TOO_SMALL. As usual, if more than one of these error codes is applicable, Cryptoki may return any of them. Only if none of them applies to any of the requested attributes will CKR_OK be returned.


The bolding is mine. My takeaway here is the following:

  • CKR_OK with CK_UNAVAILABLE_INFORMATION in ulValueLen is not a compliant PKCS#11 response (although I'm sure that there are tokens that get this wrong, as evidenced by the bug reports complaining about this)
  • assertRV(retval) on the result of C_GetAttributeValue covers this case for compliant tokens.
  • Since returning None evidently breaks stuff in various places, we should cover this case by raising an exception instead. How about overriding the CKR_OK with CKR_FUNCTION_FAILED if ulValueLen is CK_UNAVAILABLE_INFORMATION?

WDYT?

with nogil:
retval = _funclist.C_GetAttributeValue(handle, obj, &template, 1)
if retval == CK_UNAVAILABLE_INFORMATION:
if template.ulValueLen == CK_UNAVAILABLE_INFORMATION:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about this instead of returning None? (see bigger comment)

        if retval == CKR_OK and template.ulValueLen == CK_UNAVAILABLE_INFORMATION:
            retval = CKR_FUNCTION_FAILED

We can also add a comment then that this is specifically to deal with noncompliant tokens.

with nogil:
retval = _funclist.C_GetAttributeValue(handle, obj, &template, 1)
if retval == CK_UNAVAILABLE_INFORMATION:
if template.ulValueLen == CK_UNAVAILABLE_INFORMATION:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This branch shouldn't be necessary.

@minego
Copy link
Author

minego commented Jun 24, 2025 via email

@MatthiasValvekens
Copy link
Collaborator

MatthiasValvekens commented Jun 24, 2025

I don't agree with your logic about case 2. The spec doesn't indicate that it should return CKR_ATTRIBUTE_TYPE_INVALID, and in fact it seems that it would be wrong to do so if the attribute type specified is valid, but not available for that key.

It does, though 😉 See this excerpt from the passage I quoted above:

If case 2 applies to any of the requested attributes, then the call should return the value CKR_ATTRIBUTE_TYPE_INVALID.

All the situations enumerated in the spec where CK_UNAVAILABLE_INFORMATION is returned have a CKR_... error code associated with them. The spec doesn't say anything about returning CKR_OK with CK_UNAVAILABLE_INFORMATION, so that's undefined behaviour at best (i.e. up to the implementation). As such, I think CKR_FUNCTION_FAILED is appropriate in this case.

@minego
Copy link
Author

minego commented Jun 24, 2025 via email

@MatthiasValvekens
Copy link
Collaborator

On closer inspection, actually emitting CKR_OK with CK_UNAVAILABLE_INFORMATION isn't even undefined behaviour, it's strictly non-compliant on the token's part. If you follow the algorithm in the spec, CKR_OK is only allowed as the result of step 3 or 4. And in both of those cases, the spec explicitly prescribes what you should put in ulValueLen, namely the actual size of the attribute. So yes, that looks like a bug 🙂 .

I totally agree that the original behaviour in python-pkcs11 was dangerous, let's fix that by all means. Bailing with CKR_FUNCTION_FAILED certainly seems like an appropriate defensive response that is consistent with other error handling in this lib 🙂.

@minego
Copy link
Author

minego commented Jun 24, 2025 via email

@MatthiasValvekens
Copy link
Collaborator

Either is fine with me. I should have some time a few hours from now, but if you want to update the PR in the meantime, that also works for me.

@minego
Copy link
Author

minego commented Jun 24, 2025 via email

@MatthiasValvekens MatthiasValvekens force-pushed the CK_UNAVAILABLE_INFORMATION branch from 54c9bf2 to 0bc8bb3 Compare June 24, 2025 17:09
@MatthiasValvekens MatthiasValvekens force-pushed the CK_UNAVAILABLE_INFORMATION branch from 0bc8bb3 to be2d7a4 Compare June 24, 2025 17:13
@MatthiasValvekens MatthiasValvekens self-requested a review June 24, 2025 17:23
@MatthiasValvekens MatthiasValvekens merged commit be2d7a4 into pyauth:master Jun 24, 2025
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants