Commit graph

23 commits

Author SHA1 Message Date
Martin Vrachev
49aa0fc167 Make new API compatible with the Signing interface
In the securesystemslib pr https://github.com/secure-systems-lab/securesystemslib/pull/319
I added a new Signer interface with the purpose of supporting multiple
signing implementations.
Additionally, I added the SSlibSigner implementation of that interface
which implements the signing operation for rsa, ed25519 and ecdsa
schemes.
With this commit, I integrate the SSlibSigner into the new API in tuf.

Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
2021-03-10 10:57:45 +01:00
Lukas Puehringer
8e9afc96f9 Revert "Move to/from_dict metadata API methods..."
Revert an earlier commit that moved to/from_dict metadata class
model methods to a util module of the serialization sub-package.

We keep to/from_dict methods on the metadata classes because:
- It seems **idiomatic** (see e.g. 3rd-party libaries such as attrs,
pydantic, marshmallow, or built-ins that provide default or
customizable dict representation for higher-level objects).
The idiomatic choice should make usage more intuitive.
- It feels better **structured** when each method is encapsulated
within the corresponding class, which in turn should make
maintaining/modifying/extending the class model easier.
- It allows us to remove function-scope imports (see subsequent
commit).

Caveat:
Now that "the meat" of the sub-packaged JSON serializer is
implemented on the class, it might make it harder to create a
non-dict based serializer by copy-paste-amending the JSON
serializer.

However, the benefits from above seem to outweigh the disadvantage.

See option 5 of ADR0006 for further details (#1270).

Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
2021-03-04 12:46:16 +01:00
Lukas Puehringer
e1be085c3c Move to/from_dict metadata API methods to util
Add tuf.api.serialization.util module with functions to
convert between TUF metadata class model and the corresponding
dictionary representation. These functions replace the
corresponding to/from_dict classmethods.

Configure api/pylintrc to exempt '_type' from protected member
access warning, because the underscore prefix here is only used to
avoid name shadowing.

Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
2021-03-04 12:33:28 +01:00
Lukas Puehringer
240fb547af Use custom errors in serializer.json sub-package
Re-raise all errors that happen during de/serialization as custom
De/SerializationError.

Whilelist 'e', which is idiomatic for error, in api/pylintrc, and
inline exempt broad-except, which are okay if re-raised.

Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
2021-03-04 12:33:28 +01:00
Lukas Puehringer
499f1c858e Adopt serialization sub-package in metadata API
- Rename Metadata methods:
  - to_json_file -> to_file
  - from_json_file -> from_file
- Remove Metadata.from_json/to_json
- Remove Signed.to_canonical_bytes
- Accept optional de/serializer arguments:
  - from_file (default: JSONDeserializer)
  - to_file (default: JSONSerializer)
  - sign, verify (default: CanonicalJSONSerializer)
- inline disable pylint cyclic-import checks

Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
2021-03-04 12:33:18 +01:00
Joshua Lock
d144141ec7 tests: remove check for python >= 3.6 in test_api
Signed-off-by: Joshua Lock <jlock@vmware.com>
2021-03-03 09:38:39 +00:00
Martin Vrachev
028d1bc9f7 Make "utils" import more definite
Currently, we are importing the "utils" module in tests/utils
with "import utils".
This could become a problem when there is another module with
the same general name "utils" and could lead to import mistakes.

Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
2020-11-23 22:17:31 +02:00
Teodora Sechkova
5bfd9dd94c
Add tests for root and targets metadata
Add test cases for Root(Signed) and Targets(Signed) classes.

Signed-off-by: Teodora Sechkova <tsechkova@vmware.com>
2020-11-09 11:38:26 +02:00
Teodora Sechkova
fe439d2014
Fix passing dictionaries by reference in TestMetadata
Use deepcopy to ensure that the dictionaries with expected data
are not referencing the same memory as the tested ones.

Add a check asserting that metadata is not equal prior to its
update.

Signed-off-by: Teodora Sechkova <tsechkova@vmware.com>
2020-11-09 11:38:25 +02:00
Joshua Lock
38a86393c2 Make unit test files executable
It's convenient to be able to run unit test scripts directly, rather than
having to pass them as arguments to Python. This is already possible for
several of our unit tests, make it possible for all by setting the execute
bit.

Signed-off-by: Joshua Lock <jlock@vmware.com>
2020-10-05 10:36:31 +01:00
Jussi Kukkonen
03b15fb4be tests: Configure logging for all test files
all test_*.py files now accept zero or more '-v' to increase tuf
logging level. The default is now ERROR.

default: ERROR
"-v":    ERROR, but unittest prints test names
"-vv":   WARNING
"-vvv":  INFO
"-vvvv": DEBUG

Example to run a single test with DEBUG level:
  python3 test_updater.py -vvvv TestUpdater.test_4_refresh

Also make test_log.py restore the log level it modifies during test.

Fixes #1093

Signed-off-by: Jussi Kukkonen <jkukkonen@vmware.com>
2020-09-15 21:36:50 +03:00
Lukas Puehringer
73dd72d54d Raise on bad signature count in Metadata.verify
Change Metadata.verify(key) behavior to raise an exception if
none or multiple signatures for the passed key are found on the
Metadata object.

Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
2020-09-10 16:18:28 +02:00
Lukas Puehringer
387169fc11 Add from_json metadata convenience wrapper
Add convenience wrapper that takes a json string and passes it
to from_dict to create a Metadata object.

Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
2020-09-10 16:18:28 +02:00
Lukas Puehringer
f63dce6ddd Refactor metadata constructors and add factory
This commit better separates the Metadata class model from the
Metadata wireline format, by tailoring the constructors
towards class-based parameters and adding an additional
factory classmethod that creates Metadata objects based on the
wireline json/dictionary metadata representation. (pythonic
way of constructor overloading).

This 'from_dict' factory method recurses into the 'from_dict'
methods of each contained complex field/attribute that is also
represented by a class. Currently 'signed' is the only such
attribute.

This commit further:
- Changes optional constructor keyword arguments to mandatory
positional arguments: Reduces code and simplifies usage by
restricting it. For now, users are unlikely to call
constructor directly anyway, but the 'from_dict' factory (or
its 'from_json_file' wrapper) instead.

- Removes Signed.__expiration (datetime) vs. Signed.expires
(datestring) dichotomy: Keeping only one representation of the
same attribute in memory makes the interface simpler and less
ambiguous. We choose the datetime object, because it is more
convenient to modify. Transformation from and to the string
format required by the tuf wireline format is performed in the
corresponding metadata de/serialization methods, i.e.
('to_dict' and 'from_dict').

Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
2020-09-10 16:18:28 +02:00
Lukas Puehringer
f738ea0273 Rename tuf metadata interface methods
Consistenly rename de/serialization interface methods, using
a 'from_' and 'to_' prefix.

read_from_json -> from_json_file
write_to_json  -> to_json_file
as_json        -> to_json
as_dict        -> to_dict
signed_bytes   -> to_canonical_bytes

The latter is also changed from a property to a method for
consistency with the other serialization methods.

Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
2020-09-10 16:18:28 +02:00
Lukas Puehringer
e61ae1bea3 Remove Signed.read_from_json metadata method
Remove metadata factory on Signed class, for the sake of API
simplicity/non-ambiguity, i.e. it's enough to have one
way of loading any Metadata, that is:
Metadata.read_from_json

Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
2020-09-10 16:18:28 +02:00
Lukas Puehringer
21de660b66 Remove comments and unify quotes in api tests
Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
2020-09-10 16:18:28 +02:00
Lukas Puehringer
08bdc171e4 Add simple sign + verify Metadata methods (+tests)
Add simple methods to create or verify signatures of the
canonical_signed property of a Metadata object.

See corresponding docstrings for behavior and design
considerations.

The commit also adds tests and updates the test setup to load
some test keys into memory.

Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
2020-09-10 16:18:19 +02:00
Lukas Puehringer
5cc73353fa Add metadata model class and method docstrings
Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
2020-09-10 16:09:22 +02:00
Lukas Puehringer
088e94055f Replace _get_written_metadata with as_json method.
Add simple as_json Metadata method and use it instead of repository
lib's internal _get_written_metadata function in write_to_json.

This commit further adds code documentation and the possibility to
write compact json by excluding whitespace to write_to_json, and
also removes a call to the sign method from write_to_json.

The commit also adds tests.

Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
2020-09-10 15:59:10 +02:00
Lukas Puehringer
e997097d1c Add generic Metadata.read_from_json class method
Add generic read from json class method that returns a Metadata
object with a signed field that contains the appropriate Signed
subclass, based on the signed._type field of the read metadata.

Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
2020-09-10 15:59:10 +02:00
Lukas Puehringer
b1dd3d6787 Skip api tests on Python < 3.6
The new metadata module uses constructs that are only available
on Python >= 3.6 (typing, f-format strings, etc.).

Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
2020-09-10 15:59:01 +02:00
Lukas Puehringer
17f08ad200 Add simple TUF role metadata model (WIP)
Add metadata module with container classes for TUF role metadata, including
methods to read/serialize/write from and to JSON, perform TUF-compliant
metadata updates, and create and verify signatures.

The 'Metadata' class provides a container for inner TUF metadata objects (Root,
Timestamp, Snapshot, Targets) (i.e. OOP composition)

The 'Signed' class provides a base class to aggregate common attributes (i.e.
version, expires, spec_version) of the inner metadata classes. (i.e. OOP
inheritance). The name of the class also aligns with the 'signed' field of
the outer metadata container.

Based on prior observations in TUF's sister project in-toto, this architecture
seems to well represent the metadata model as it is defined in the
specification (see in-toto/in-toto#98 and in-toto/in-toto#142 for related
discussions).

This commits also adds tests.

**TODO: See doc header TODO list**

**Additional design considerations**
(also in regards to prior sketches of this module)

 - Aims at simplicity, brevity and recognizability of the wireline metadata
   format.

 - All attributes that correspond to fields in TUF JSON metadata are public.
   There doesn't seem to be a good reason to protect them with leading
   underscores and use setters/getters instead, it just adds more code, and
   impedes recognizability of the wireline metadata format.

 - Although, it might be convenient to have short-cuts on the Metadata class
   that point to methods and attributes that are common to all subclasses of
   the contained Signed class (e.g. Metadata.version instead of
   Metadata.signed.version, etc.), this also conflicts with goal of
   recognizability of the wireline metadata. Thus we won't add such short-cuts
   for now. See:
   https://github.com/theupdateframework/tuf/pull/1060#discussion_r452906629

 - Signing keys and a 'consistent_snapshot' boolean are not on the targets
   metadata class. They are a better fit for management code. See:
   https://github.com/theupdateframework/tuf/pull/1060#issuecomment-660056376,
   and #660.

 - Does not use sslib schema checks (see TODO notes about validation in
   doc header)

 - Does not use existing tuf utils, such as make_metadata_fileinfo,
   build_dict_conforming_to_schema, if it is easy and more explicit to
   just re-implement the desired behavior on the metadata classes.

 - All datetime's are treated as UTC. Since timezone info is not captured in
   the wireline metadata format it should not be captured in the internal
   representation either.

 - Does not use 3rd-party dateutil package, in order to minimize dependency
   footprint, which is especially important for update clients which often have
   to vendor their dependencies.
   However, compatibility between the more advanced dateutil.relativedelta (e.g
   handles leap years automatically) and timedelta is tested.

 - Uses PEP8 indentation (4 space) and Google-style doc string instead of
   sslab-style. See
   https://github.com/secure-systems-lab/code-style-guidelines/issues/20

 - Does not support Python =< 3.5

Co-authored-by: Trishank Karthik Kuppusamy <trishank.kuppusamy@datadoghq.com>
Co-authored-by: Joshua Lock <jlock@vmware.com>
Co-authored-by: Teodora Sechkova <tsechkova@vmware.com>
Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
2020-08-20 12:14:40 +02:00