signer: Add abstract Key class, implement private key uri scheme for Signer#456
signer: Add abstract Key class, implement private key uri scheme for Signer#456lukpueh merged 21 commits intosecure-systems-lab:masterfrom
Conversation
The scheme allows instantiating signers and signing with them
without knowing the signer or privtae key type beforehand.,
Signers can now be used like this:
# demo setup
pubkey = generate_ecdsa_key()
privkey = pubkey["keyval"].pop("private")
os.environ["myprivatekey"] = privkey
# sign: Correct Signer subclass is chosen based on the URI
signer = Signer.from_priv_key_uri("envvar://myprivatekey", pubkey)
sig = signer.sign(b"data")
Just three schemes are supported by default but more can be added here
and exernally, in applications.
Default schemes:
envvar: read private key content from environment variable
file: read private key content from file
encfile: read encrypted private key content from file, decrypt with
passphrase from application
This is copied from python-tuf with following changes * verify_signature() is left in python-tuf as Metadata-related * is_verified() is added instead * type of keyval is changed from Dict[str, str] to Dict[str, Any] * Some docstrings made more reasonable for SSLib Signer.from_priv_key_uri() now takes a Key as argument. SSlibSigner constructor still takes a classic keydict as constructor argument and not a Key (in order to not break API) but that is now documented as an implementation detail.
python-tuf has an extensive test suite for Metadata in general: * I don't think python-tuf should stop testing Key just because it's now in securesystemslib * Maybe it's not necessary to copy e.g. all serialization tests here? Still, added a few basic tests for Key. Key is also used in the Signer tests.
|
Results from chat with Lukas:
This is quite a bit more than just moving the Key class... but it fits in well with Signer change as they are both dispatcher-style abstractions (for Key and Signer respectively) |
The idea is to allow more Key implementations, but SSlibKey provides the current implementations.
GPGSigner and GPGKey are not in the default dispatch list as the serialization formats they produce are not compatible with TUF or in-toto specifications Tests are very smoke testy so far
verify_signature now has two exceptions:
class UnverifiedSignatureError(Error):
class VerificationError(UnverifiedSignatureError):
First one for those who just want to know if verify succeeded.
Second one for those who want to also know if process failed somehow.
|
This ballooned "a bit"... I've updated the description, hoping it makes sense to others. |
|
Oh and I forgot to mention: Most of the GPGKey implementation in here comes from https://github.com/in-toto/securesystemslib/ so is likely @PradyumnaKrishna's work: if this PR looks like a path forward, should make sure he gets credited (I can try editing the commit history so authorship is visible in git) |
|
A couple of high-level comments:
Some thoughts about fixing gpg issues
|
|
I think we can do both:
but I certainly wouldn't oppose to in-toto keeping the GPGKey and GPGSigner in their code base -- and with this architecture it would be quite easy As mentionedin the other reply, GPGKey does support |
|
I think the special keyid matching is not too much to ask from the |
👍 Let's do that in a follow-up PR.
I suggest to remove it from securesystemslib, for these reasons (as discussed above):
|
Yes, this should be easy if it's only needed in in-toto. The reason why we defined the |
Signer and Key are now abstract and can have multiple implementations that get dispatched by the base classes. The current GPG implementation is just non-compliant enough that it is not included in the dispatch. Plan is: * move GPGSigner to intoto, add GPGKey in intoto: this allows intoto to keep using this implementation without too much pain * Possibly implement a more compliant GPG signer and key in securesystemslib
|
Current state:
Potential review questions/improvements:
|
No it does not. |
I think it's more than just |
No, Key is still part of the python-tuf Metadata API -- it's just that it comes from securesystemslib. This is not as clear as it should be since we are not explicit about API: I think it would make sense to use So currently python-tuf users can do Now that I think about it the |
|
Related comment on Signer:
the former is #463. The latter idea (just using |
joshuagl
left a comment
There was a problem hiding this comment.
I really like this, nice work! I left a couple of minor comments, notably a request to document the dynamic dispatch method and how folks add their own implementations of the abstract base classes and wire them in.
* Fix the incorrect metaclass syntax * Also refactor constructor so it is shorter
|
fixed a few latest comments (thanks!): No real functional changes here. |
There is (at least currently) no promise that Signer implementations do not raise unexpected errors.
|
Ok, I think I'm now done. All future tickets are filed, PR should be ready. |
lukpueh
left a comment
There was a problem hiding this comment.
This is so neat! Many thanks, Jussi. I'm approving, although we should probably check for None instead of Falseyness when creating the default self.unrecognized_fields value. But this is no blocker.
Also, there is an annotation inconsistency in Key and Signature unrecognized_fields constructor argument and instance variables (Dict vs. Mapping, and type hint at declaration in one but not the other). You probably just copied those over. 🤷
* do not check falsyness of argument containers: the results are unexpected if the argument container is empty * Do not use Mapping annotation for unrecognized_fields. The original idea was that Metadata API is not changing them: this is true but we don't want to prevent users from modifying the fields...
Fixes: #447
Summary
The private key URI scheme allows application code to handle private keys in a generic way: the keytype, used signer implementation or private key storage system are not something the application needs to worry about. Example
Changelist
The user facing API additions are:
Signer.from_priv_key_uri()addedSIGNER_FOR_URI_SCHEMEandKEY_FOR_TYPE_AND_SCHEMEdefine supported signers and keysOther changes that do not really affect users
Other notes:
Signer.from_priv_key_uri()Key.from_dict()TODO later: I will file issues