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

feat: Implement full support for ECDSA and RSA keys #270

Closed

Conversation

toby-jn
Copy link
Contributor

@toby-jn toby-jn commented Apr 16, 2022

Release Notes:

Types of changes:

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Description of the changes being introduced by the pull request:

Previously support for ECDSA and RSA keys was only partially implemented:

  • Only the verifier/public key type was implemented for ECDSA.
  • ECDSA public keys were parsed as the hex encoding of the raw point serialised as ASN.1 . The TUF specification states that they should be encoded as PEM https://theupdateframework.github.io/specification/latest/#keyval-ecdsa-public.
  • The RSA signer was not fully implemented, the marshal and unmarshal methods returned not implemented errors.
  • The RSA public key mixed up the PEM encoding, it encoded as PKIX, but then set the header to RSA PUBLIC KEY which is used for PKCS1 encoding. While the spec doesn't specify which encoding should be used (and just specifies "PEM"), the python reference implementation uses PKIX for both ECDSA and RSA keys.
  • The RSA verifier attempted to parse the public key as PKCS1 and PKIX. While the spec does not make this clear, the python implementation only uses PKIX.
  • The gen-key subcommand does not allow key types to be specified, added a --type flag to allow the user to select the key type to be generated.

As well as the above fixes, some additional improvements to the library were made:

  • Defined new go types for KeyType, KeyScheme and HashAlgorithm, rather than just using strings, and fixed a few places where the key type and scheme had been mixed up.
  • Added a new data.PKIXPublicKey type which abstracts away a lot of the boiler plate for marshalling/unmarshalling public keys.

I opted not to maintain backwards compatibility as there is currently no implementation to generate ECDSA or RSA keys, and the go-tuf implementation wouldn't have worked with keys serialised according the the TUF specification, so there didn't seem any benefit to maintaining this functionality.

Please verify and check that the pull request fulfills the following requirements:

  • Tests have been added for the bug fix or new feature
  • Docs have been added for the bug fix or new feature

@toby-jn
Copy link
Contributor Author

toby-jn commented Apr 27, 2022

any chance of getting a review of this?

Copy link
Collaborator

@mnm678 mnm678 left a comment

Choose a reason for hiding this comment

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

This looks great. My only concern is the backwards compatibility issue. In the long term I think this is what we need to do (use the spec compliant key types). We could just do this patch as part of a major release. What do others think? @asraa @trishankatdatadog

@toby-jn
Copy link
Contributor Author

toby-jn commented Apr 27, 2022

Making it backwards compatible with what go-tuf was doing before wouldn't be that difficult.. however the old implementation doesn't follow the spec, and is incompatible with py-tuf and it also doesn't have the necessary functions to actually generate ecdsa/rsa keys, so for someone to have a compatibility issue here they'd have need to have done quite a lot of work outside of go-tuf to make keys in the right format.

Copy link
Contributor

@asraa asraa left a comment

Choose a reason for hiding this comment

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

One problem I see with the ECDSA keys is that if you're using an existing TUF root with ecdsa keys, your root key IDs won't match on update. This is a big problem when you're trying to sign the next root. I think we have to make this backwards compatible, maybe with a flag or an option

@trishankatdatadog
Copy link
Member

Fixes issue #223

Copy link
Contributor

@asraa asraa left a comment

Choose a reason for hiding this comment

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

Thanks! Hoping to revive this so we can get go-tuf python compliant in the next release.

I just have one proposition on supporting the old key types for a short period of time so users can have a migration plan away from it.

Let me know if you need any help! I'm happy to contribute.

@@ -23,23 +25,35 @@ form of TUF_{{ROLE}}_PASSPHRASE

Options:
--expires=<days> Set the root metadata file to expire <days> days from now.
--type=<type> Set the type of key to generate [default: ed25519].
Copy link
Contributor

Choose a reason for hiding this comment

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

could you please document the other key type possibilities? it's a bit hard to discern in the code because they are consts.

return p.key
}

func (p *p256Verifier) UnmarshalPublicKey(key *data.PublicKey) error {
func (p *ecdsaVerifier) UnmarshalPublicKey(key *data.PublicKey) error {
Copy link
Contributor

Choose a reason for hiding this comment

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

Question: To keep backwards compatibility with existing roots (at least for 1-2 releases), could we do something like rename the old ecdsaVerifier to deprecatedEcdsaVerifier, and attempt to json.Unmarshal into that one?

I'm hoping to be able to still support old verifiers.

For example, if TUF attempts to UnmarshalPublicKey on an old ecdsa key, the resulting object would return the deprecatd Public() and Marshal() as the received data.


var _ = Suite(EcdsaSuite{})

func (EcdsaSuite) TestSignVerify(c *C) {
Copy link
Contributor

Choose a reason for hiding this comment

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

if you go with backwards compatibility, could you add a test with hard-coded deprecated key material, and make sure that properties like PublicData() and Public() and Verify() still work?

@trishankatdatadog
Copy link
Member

Damn, I got busy, sorry. Let me look ASAP, maybe tonight.

@znewman01
Copy link
Contributor

I'm closing in favor of #357

Thanks for kicking this off, @toby-jn 😄

@znewman01 znewman01 closed this Sep 6, 2022
asraa added a commit that referenced this pull request Sep 7, 2022
…357)

* * fix!: ECDSA verifiers now expect PEM-encoded public keys per TUF specification
* feat: ECDSA signers are now implemented
* feat: RSA verifiers and signers are implemented

BREAKING CHANGE: ECDSA verifiers expect PEM-encoded public keys. If you rely
on previous behavior of hex-encoded public keys for verifiers, then you must
import pkg/deprecated/set_ecdsa that will allow a fallback for hex-encoded
ECDSA keys.

Co-authored-by: Asra Ali <asraa@google.com>
Co-authored-by: Toby Bristow <toby.bristow@qush.com>
Signed-off-by: Asra Ali <asraa@google.com>

* add comment

Signed-off-by: Asra Ali <asraa@google.com>

Signed-off-by: Asra Ali <asraa@google.com>
Co-authored-by: Toby Bristow <toby.bristow@qush.com>
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.

None yet

5 participants