-
Notifications
You must be signed in to change notification settings - Fork 68
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
Issue #44: Option to remove False flags from the C_UnwrapKey template. #45
Conversation
214a38d
to
511ee1f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, but I think this is slightly the wrong solution. I think it would be better suited on one of the earlier calls that sets up the default template. Or maybe we should just not pass False in to any default template.
511ee1f
to
0a849d4
Compare
New squashed commit - for I'm not familiar with Cython, so unsure where |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would take this one step further, into a function that took capabilities
as an argument and returned a dictionary, of only the True
values. And then use it everywhere we mix capabilities into the template.
0a849d4
to
1b8a83c
Compare
Added a common function to convert to dict, and mix this function into the methods. I see a problem with this commit: it breaks test_sessions.py:SessionTests::test_generate_key because Maybe capabilities can be an int or (int, include_mask)-tuple so that the flag is returned in the dict even if False, what do you think?
If I change the test as below I can get the same test passes as master:
|
Added a commit to fix a test. |
tests/test_sessions.py
Outdated
@@ -53,7 +53,7 @@ def test_generate_key(self): | |||
key = session.generate_key(pkcs11.KeyType.AES, 128, | |||
label='MY KEY', | |||
id=b'\1\2\3\4', | |||
capabilities=0) | |||
template={pkcs11.Attribute.ENCRYPT: False}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm.. does this break an assumption of the library, if you're not set the capability is that false or default?
Maybe we're thinking about this all wrong, and you get the default OR the capabilities you've set only, without merging.
So capabilities=None
-> default set of True's, no falses. capabilities is not None
Trues for set capabilities. No falses. That way this test won't have to be changed. And for anything not specified you get the HSM's default, which should be sensible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this test we don't know the HSM defaults so we explicitly need to set ENCRYPT to False, this is achieved by the current behaviour which set all flags to False.
Not sure what you mean by "So capabilities=None -> default set of True's, no falses. capabilities is not None Trues for set capabilities. No falses." Won't we still have to force the flag to False somehow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what I mean either. I think, I've been thinking about this all wrong.
We've got 3 states: true, false and left-out (default). In this test we wanted to pass False
so we unset the capability. That is intuitive to me.
This has worked for everything except for HSMs that don't accept the Attribute at all. There have been a few times where it could have been useful to remove a value out of the template. Perhaps what we need is a new constant DEFAULT
, which is filtered out of the final merged template.
Something like this:
template={
pkcs11.Attribute.UNWANTED_ATTRIBUTE: pkcs11.DEFAULT
}
We could then filter out all DEFAULT
values from the remaining template. I'm happy to code this up if you're not keen.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I have tried to code this up - there is no change to the tests, capabilities=N
does what it does before and sets the library default flags.
If the user really does not want the attr sent to the HSM, the library can be overridden with the semantics you suggest:
# my HSM does not want ENCRYPT VERIFY WRAP on private keys but
# for unwrap the library sets all 7 flags to either True/False, so...
obj.unwrap_key( .... template={Attribute.ENCRYPT: pkcs11.DEFAULT,
Attribute.VERIFY: pkcs11.DEFAULT,
Attribute.WRAP: pkcs11.DEFAULT})
4b72364
to
4f0f1e7
Compare
pkcs11/constants.py
Outdated
Wraps DEFAULT so we don't accidentally coincide | ||
with a desired value of 0xFFFFFFFF | ||
""" | ||
DEFAULT = 0xFFFFFFFF |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the sentinel object pattern. IntEnum
is especially dangerous because 0xffffffff might be a valid value for something (indeed I think it is for mantissa).
DEFAULT = object()
if value is DEFAULT:
....
pkcs11/_pkcs11.pyx
Outdated
@@ -293,6 +293,18 @@ class SearchIter: | |||
self.session._operation_lock.release() | |||
|
|||
|
|||
def _finalize_template(template_, template): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like to avoid functions that mutate their inputs. I would do this like:
def merge_templates(default_template, *user_templates):
template = default_template.copy()
for user_template in user_templates:
if user_template is not None:
template.update(user_template)
return {
key: value
for key, value in template.items()
if value is not DEFAULT
}
It's also a good opportunity to name things what they are.
pkcs11/_pkcs11.pyx
Outdated
@@ -348,7 +360,7 @@ class Session(types.Session): | |||
Attribute.TOKEN: store, | |||
Attribute.PRIME_BITS: param_length, | |||
} | |||
template_.update(template or {}) | |||
_finalize_template(template_, template) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You conceivably could then remove all of the weird underscore confusion with something like
attrs = AttributeList(merge_templates({
default: template,
goes: here,
}, template))
Which I think would make the code a lot more readable.
You could also try making this a @classmethod
on AttributeList
(e.g. from_template
). Doing this means you would have to deal with Cython's binding nonsense, see the tests for examples.
5eba1b7
to
0bde0a5
Compare
Using the non-mutating function recommendation as the MVP path. |
@@ -11,6 +11,9 @@ | |||
from aenum import IntEnum, IntFlag, unique | |||
|
|||
|
|||
# sentinel value to remove attributes from template | |||
DEFAULT = object() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a docstring for this so that it turns up in the documentation :)
Looks good. If you can make sure |
and use the HSM default values Addresses pyauth#44
Great - done! Thanks. |
Thanks for this. I'll do a release as soon as I've sorted out the Windows unit testing. |
Addresses #44.
Option to control the set of flags included in the template sent with C_UnwrapKey: flags that are False are removed.
Needed for some HSMs that don't accept all the flags even if they are set to False.