Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question about C_GetAttributeValue implementation #292

Closed
vsenko opened this issue Feb 22, 2017 · 8 comments
Closed

Question about C_GetAttributeValue implementation #292

vsenko opened this issue Feb 22, 2017 · 8 comments

Comments

@vsenko
Copy link

vsenko commented Feb 22, 2017

Good day!

I have a question regarding implementation of function C_GetAttributeValue in SoftHSMv2, specifically about how attributes, which values are arrays of attributes, are handled.

According to the test: https://github.com/opendnssec/SoftHSMv2/blob/master/src/lib/test/ObjectTests.cpp#L1909)
SoftHSMv2 allows to pass to C_GetAttributeValue an array attribute value (CKA_WRAP_TEMPLATE for example) as an array of CK_ATTRIBUTE structures with CK_ATTRIBUTE_TYPE type set to zero (https://github.com/opendnssec/SoftHSMv2/blob/master/src/lib/test/ObjectTests.cpp#L1967) and C_GetAttributeValue will set CK_ATTRIBUTE_TYPE type in the structures to appropriate types.

But I can not find such behavior in the specification: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html

As far as I understand the specification of C_GetAttributeValue in context of a special case when template (pTemplate) value is an array, C_GetAttributeValue can be called:

  • with NULL as pTemplate attribute value (CK_VOID_PTR pValue), then C_GetAttributeValue will report size of buffer necessary to hold the array of subattributes of corresponding attribute;
  • with an array of CK_ATTRIBUTE structures in which CK_ATTRIBUTE_TYPE type are set to specific types and CK_VOID_PTR pValue are set to NULL, then C_GetAttributeValue will report sizes of buffers necessary to hold the values of subattributes;
  • with an array of CK_ATTRIBUTE structures in which CK_ATTRIBUTE_TYPE type are set to specific types and CK_VOID_PTR pValue are set to pointers, then C_GetAttributeValue will return values of subattributes.

C_GetAttributeValue obtains the value of one or more attributes of an object. hSession is the session’s handle; hObject is the object’s handle; pTemplate points to a template that specifies which attribute values are to be obtained, and receives the attribute values; ulCount is the number of attributes in the template.
For each (type, pValue, ulValueLen) triple in the template, C_GetAttributeValue performs the following algorithm:

  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.
In the special case of an attribute whose value is an array of attributes, for example CKA_WRAP_TEMPLATE, where it is passed in with pValue not NULL, then if the pValue of elements within the array is NULL_PTR then the ulValueLen of elements within the array will be set to the required length. If the pValue of elements within the array is not NULL_PTR, then the ulValueLen element of attributes within the array MUST reflect the space that the corresponding pValue points to, and pValue is filled in if there is sufficient room. Therefore it is important to initialize the contents of a buffer before calling C_GetAttributeValue to get such an array value. If any ulValueLen within the array isn't large enough, it will be set to CK_UNAVAILABLE_INFORMATION and the function will return CKR_BUFFER_TOO_SMALL, as it does if an attribute in the pTemplate argument has ulValueLen too small. Note that any attribute whose value is an array of attributes is identifiable by virtue of the attribute type having the CKF_ARRAY_ATTRIBUTE bit set.

So the question is: Is there any source of documentation that specific implementation of function C_GetAttributeValue in SoftHSMv2 relies on?

@bellgrim
Copy link
Contributor

bellgrim commented Feb 22, 2017

Ok, so we agree that all the behavior, except "CK_ATTRIBUTE structures with CK_ATTRIBUTE_TYPE type set to zero", is according to the specification. Right? And this is what you are asking about?

PKCS#11 does not explicitly say how the CK_ATTRIBUTE_TYPE within the array should be handled. However, one could say that it is part of the attribute value for e.g. CKA_WRAP_TEMPLATE that we want to extract using C_GetAttributeValue() and should thus be set by the PKCS#11 library. If we forget that we were the ones who created the object with its CKA_WRAP_TEMPLATE, how would we know the value of each CK_ATTRIBUTE_TYPE in the attribute array? This is why we have C_GetAttributeValue() to get this information.

If this was not set by the PKCS#11 library, all we would know are pointers and data lengths to unknown attributes within the template. Also, the order of the attributes are undefined.

@dengert
Copy link

dengert commented Feb 23, 2017

PKCS#11 2.40 has:
#define CKA_CLASS 0x00000000UL
So requesting an attribute of CK_ATTRIBUTE_TYPE = 0 is requesting the CKA_CLASS of the object.

#define CKF_ARRAY_ATTRIBUTE 0x40000000UL

Note that any attribute whose value is an array of attributes is identifiable by virtue of the attribute
type having the CKF_ARRAY_ATTRIBUTE bit set.

There are only 3 attributes that are arrays of other attributes.

#define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000211UL)
#define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000212UL)
#define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE|0x00000600UL)

PKCS#11 also defines:
#define CKO_VENDOR_DEFINED 0x80000000UL
#define CKA_VENDOR_DEFINED 0x80000000UL

So it could be possible to define objects that have one or more arrays of attributes
of which one or more of the attributes are array of attributes to any depth.

But for now, there are only 3 attributes that are arrays of other attributes.

@bellgrim
Copy link
Contributor

But we are not asking about a specific attribute within the array. We are asking about all attributes in the array. Any implementation should thus ignore the value of the attribute type in the array.

As I said earlier, we have no way of knowing which type value we should use as the content of the array is unknown. Setting it to CK_ATTRIBUTE_TYPE = 0 or any other value should have no meaning.

@vsenko
Copy link
Author

vsenko commented Feb 23, 2017

My opinion is that SoftHSMv2 approach adds ambiguity to the way C_GetAttributeValue() can be called. At first I'd like to discuss common attributes. Let's assume the following object for example:

[
  { CKA_CLASS; CKO_DATA; __class_value_size__ },
  { CKA_VALUE, "some value"; __data_value_size__ } // for simplicity lets assume it a string
]

According to my understanding of specification it is correct to pass the following pTemplate to C_GetAttributeValue():

[
  { CKA_CLASS; __pointer_1__; __class_value_size__ },
  { CKA_CLASS; __pointer_2__; __class_value_size__ }
]

And C_GetAttributeValue() should update buffers that pointer_1 and pointer_2 point to with value CKO_DATA.

If we will develop this approach to array attributes, then the call to C_GetAttributeValue() with sub pTemplate attributes set with zeros should mean that the caller wants to obtain the same sub value (value of CKA_CLASS to be precise) several times. But SoftHSMv2 approach defines a very specific behavior in this situation.

I would also like to introduce a way to figure out types of sub attributes. The caller can definitely figure out quantity of sub attributes by requesting the size of array attribute. Then the caller can enumerate all available in PKCS#11 attribute classes and filter the ones that are not present in sub template:

  1. 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.
    

@bellgrim
Copy link
Contributor

I do not see any problem with this behavior w.r.t. PKCS#11. PKCS#11 has not clearly defined the handling of array attributes and we have made an interpretation that fits the handling of other types of attributes.

The behavior of getting an array attribute:

  1. Call C_GetAttributeValue() with { CKA_WRAP_TEMPLATE, NULL_PTR, 0 } to get the size of the attribute.
  2. The PKCS#11 library will set ulValueLen to number of attributes * sizeof(CK_ATTRIBUTE)
  3. We make sure we have an empty array attribute with a size that match ulValueLen.
  4. Call C_GetAttributeValue() with CKA_WRAP_TEMPLATE pointing to an array of attributes with NULL_PTR.
  5. The PKCS#11 library will set type and ulValueLen for each attribute in the array to match the length of each attribute.
  6. We will make sure to allocate space for each attribute in the array.
  7. Call C_GetAttributeValue() with CKA_WRAP_TEMPLATE pointing to an array of attributes with allocated memory.
  8. The PKCS#11 library will set the value of each attribute in the array.

Do you have examples from other PKCS#11 libraries and how they are handling attribute arrays?

@vsenko
Copy link
Author

vsenko commented Feb 23, 2017

Thank you for explanations, but I would like to discuss two possible issues:

  • What if the caller knows types and quantity of sub attributes and he want to find out only sizes of their values. Probably he will call 4. and pass sub template with attributes types already set to something and they will be arranged in some specific order. Will SoftHSMv2 implementation preserve sub attribute types? Or it will reset them anyway?
  • What will happen if in 4. the caller will allocate memory not for all the sub attributes, but only for some of them. For example there are 5 attributes in sub template and the caller is confident in their types (somehow), so he wants to get values of only 3 of them.

@bellgrim
Copy link
Contributor

You can see the behavior here:

static CK_RV retrieveArray(CK_ATTRIBUTE_PTR pTemplate, const std::map<CK_ATTRIBUTE_TYPE,OSAttribute>& array)

If pValue for all array attributes are set to NULL_PTR, then all type and ulValueLen will be updated. Thus resetting any incoming type value.

If the attribute in the array template is too small then SoftHSM will return with CKR_BUFFER_TOO_SMALL. If the array template will not fit all attributes, then it will return with CKR_BUFFER_TOO_SMALL. If the array template has an attribute that is not part of the array attribute, then it will return CKR_ATTRIBUTE_TYPE_INVALID.

Please read the code and experiment with SoftHSM for more details.

@vsenko
Copy link
Author

vsenko commented Feb 24, 2017

Thank you again for explanations, and excuse me for bothering you!

By the way I am aware only of two OSS PKCS11 implementations:

But both of them do not support array attributes.

@vsenko vsenko closed this as completed Feb 24, 2017
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

No branches or pull requests

3 participants