diff --git a/pw_software_update/BUILD.bazel b/pw_software_update/BUILD.bazel new file mode 100644 index 000000000..423ca1f7e --- /dev/null +++ b/pw_software_update/BUILD.bazel @@ -0,0 +1,28 @@ +# Copyright 2021 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +load("@rules_proto//proto:defs.bzl", "proto_library") + +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +proto_library( + name = "update_bundle_proto", + srcs = [ + "pw_software_update_protos/tuf.proto", + "pw_software_update_protos/update_bundle.proto", + ], + strip_import_prefix = "//pw_software_update", +) diff --git a/pw_software_update/BUILD.gn b/pw_software_update/BUILD.gn new file mode 100644 index 000000000..200545d41 --- /dev/null +++ b/pw_software_update/BUILD.gn @@ -0,0 +1,28 @@ +# Copyright 2021 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +import("//build_overrides/pigweed.gni") + +import("$dir_pw_protobuf_compiler/proto.gni") + +config("default_config") { + include_dirs = [ "public" ] +} + +pw_proto_library("protos") { + sources = [ + "pw_software_update_protos/tuf.proto", + "pw_software_update_protos/update_bundle.proto", + ] +} diff --git a/pw_software_update/pw_software_update_protos/tuf.proto b/pw_software_update/pw_software_update_protos/tuf.proto new file mode 100644 index 000000000..1a4bc9a70 --- /dev/null +++ b/pw_software_update/pw_software_update_protos/tuf.proto @@ -0,0 +1,275 @@ +// Copyright 2021 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +syntax = "proto3"; + +package pw.software_update; + +import "google/protobuf/timestamp.proto"; + +// Metadata for a particular TUF role (e.g. targets metadata). +// Was TufMetadata +message SignedMetadata { + // Serialized Metadata message that is the data portion of the metadata. + bytes serialized_metadata = 1; + + // Signature over the data portion for this metadata (serialized signed + // field). + repeated Signature signatures = 2; +} + +// This content is signed. +message Metadata { + // The top level role for this metadata. + Role type = 1; + + // Version number of the TUF Specification. + // Follows the Semantic Versioning 2.0.0 (semver) format. Metadata is + // written according to this version, and clients MUST verify that + // "spec_version" matches the expected version number. + // E.g. "1.0.0". + string spec_version = 2; + + // Metadata file version. + // Clients MUST NOT replace a metadata file with a version number less than + // the one currently trusted. + uint32 version = 3; + + // Expiration time for the metadata. + // Indicates when this metadata should be considered expired and no longer + // trusted by clients. Notice the TUF Specification defines this as a JSON + // string following the ISO 8601 standard. The expected format of the date and + // time string is "YYYY-MM-DDTHH:MM:SSZ". Time is always in UTC, and the "Z" + // time zone designator is attached to indicate a zero UTC offset. + // E.g. "2030-08-26T16:48:27Z". + optional google.protobuf.Timestamp expires = 4; + + // Contents specific to a role. + // Notice this part is different from the structure of the TUF Specification. + oneof role { + // Fields only present in root metadata. + RootContent root = 5; + + // Fields only present in targets metadata. + TargetsContent targets = 6; + + // Fields only present in snapshot metadata. + SnapshotContent snapshot = 7; + + // Fields only present in timestamp metadata. + TimestampContent timestamp = 8; + } + + // This is NOT a part of the TUF Specification. + reserved 9 to 31; // Reserved for TUF Specification changes. + + reserved 32 to 64; // Reserved for future Pigweed usage. + + reserved 65 to 255; // Reserved for project-specific usage. +} + +message Signature { + // ID of the key used for signing. + // E.g. "cb3fbd83df4ba2471a736b065650878280964a98843ec13b457a99b2a21cc3b4". + bytes keyid = 1; + + // The signature of the bytes form of Signed. + // E.g. "a312...b306". + bytes sig = 2; +} + +// Enum of TUF top level roles. +enum Role { + // Never use this in any TUF metadata. + UNKNOWN_ROLE = 0; + ROOT = 1; + SNAPSHOT = 2; + TIMESTAMP = 3; + TARGETS = 4; + MIRROR = 5; +} + +message Key { + // ID of the key used for signing. + // E.g. "cb3fbd83df4ba2471a736b065650878280964a98843ec13b457a99b2a21cc3b4". + bytes key_id = 1; + // Digest of the cryptographic hash function computed on the target file. + KeyContent key_content = 2; +} + +message RootContent { + // Whether the repo supports consistent snapshots. If the repo has frequent + // updates, you should set this to true. + bool consistent_snapshot = 1; + + // Map from Keyid to KeyContent. + // Keyid is a unique identifier that identifies a cryptographic key. + // List of cryptographic keys used by this repository. + repeated Key keys = 2; + + // Map from Role (eg "root") to RoleContent. + // List of cryptographic keys used to sign each metadata type. + message RoleMapping { + Role role = 1; + RoleContent content = 2; + } + RoleMapping roles = 3; +} + +message TargetsContent { + // Map from target file name to TargetFileContent. + // Target name can be an arbitrary name or a path that describes where the + // file lives relative to the base directory of the repository, + // e.g. "path/to/amber_tools/0". + map targets = 1; +} + +message SnapshotContent { + // Map from Target metadata file name to MetaFileContent. + // File name can be an arbitrary name or a full file name with relative path. + // This map should contain an entry for the top level targets role and all + // delegated roles. + map meta = 1; + + // This is NOT a part of the TUF Specification. + reserved 3 to 15; // Reserved for TUF Specification changes. + + reserved 16 to 31; // Reserved for future Pigweed usage. + + reserved 32 to 255; // Reserved for future project-specific usage. +} + +message TimestampContent { + // Map from snapshot metadata file name to MetaFileContent. + // File name can be an arbitrary name or a full file name with relative path. + // This map should contain only one entry, for the top level snapshot role. + map meta = 1; +} + +// Identifies an asymmetric cryptographic key. +message KeyContent { + // Denotes a public key signature system, such as RSA or ECDSA. + KeyType key_type = 1; + + // Denotes the signature scheme corresponding to the key type. For example: + // "rsassa-pss-sha256" or "ecdsa-sha2-nistp256". + KeyScheme scheme = 2; + + // Stores the public portion of the referenced cryptographic key. + Keyval keyval = 3; +} + +// The cryptographic keys belonging to a specific role. For example, list of +// keyids belonging to the top level role "root". +message RoleContent { + // Set of Keyid's. + // Keyid is a unique identifier that identifies a cryptographic key. + // E.g. "f2d5020d08aea06a0a9192eb6a4f549e17032ebefa1aa9ac167c1e3e727930d6". + repeated bytes keyids = 1; + + // Threshold of signatures required to trust given file. + // In other words; the number of keys of that role whose signatures are + // required in order to consider a file as being properly signed by that role. + uint32 threshold = 2; +} + +enum HashFunction { + // Never use this in any TUF metadata. + UNKNOWN_HASH_FUNCTION = 0; + + SHA256 = 1; +} + +message Hash { + HashFunction function = 1; + // Digest of the cryptographic hash function computed on the target file. + bytes hash = 2; +} + +// Descriptor for a file stored in this repository. Linked to from targets +// metadata. +message TargetFileContent { + // Size of the target file (element payload) in bytes. This the size as stored + // in the bundle. The final applied size can be different due to optional + // compression. + uint64 length = 1; + + // Map from algorithm name to Hash. + // Algorithm name is the name of a cryptographic hash function. E.g. "sha256". + // The Hash string is the hex digest of the cryptographic function computed on + // the target file. E.g. + // "65b8c67f51c993d898250f40aa57a317d854900b3a04895464313e48785440da". + repeated Hash hashes = 2; + + // This is NOT a part of the TUF Specification. + reserved 3 to 15; // Reserved for TUF Specification changes. + + reserved 16 to 31; // Reserved for future Pigweed usage. + + reserved 32 to 255; // Reserved for future project-specific usage. +} + +message MetaFileContent { + // Metadata file version. E.g. 3. + uint32 version = 1; + + // Size of the target file in bytes. + uint64 length = 2; + + // Map from algorithm name to Hash. + // Algorithm name is the name of a cryptographic hash function. E.g. "sha256". + // The Hash is the hex digest of the cryptographic function computed on the + // target file. E.g. + // "65b8c67f51c993d898250f40aa57a317d854900b3a04895464313e48785440da". + repeated Hash hashes = 2; +} + +enum KeyType { + // Never use this in any TUF metadata. + UNKNOWN_KEY_TYPE = 0; + + RSA = 1; + + ED25519 = 2; + + ECDSA_SHA2_NISTP256 = 3; +} + +enum KeyScheme { + // Never use this in any TUF metadata. + UNKNOWN_KEY_SCHEME = 0; + + // RSA Probabilistic signature scheme with appendix. + // The underlying hash function is SHA256. + // In TUF Specification, this is referred to as "rsassa-pss-sha256". + RSASSA_PSS_SHA256_SCHEME = 1; + + // Elliptic Curve digital signature algorithm based on Twisted Edwards curves. + // See https://ed25519.cr.yp.to/. + // In TUF Specification, it is referred to as "ed25519". + ED25519_SCHEME = 2; + + // Elliptic Curve Digital Signature Algorithm with NIST P-256 curve signing + // and SHA-256 hashing. See + // https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm In + // TUF Specification, it is referred to as "ecdsa-sha2-nistp256". + ECDSA_SHA2_NISTP256_SCHEME = 3; +} + +message Keyval { + // The serialized public key for this cryptographic algorithm. + // Encoded using the common format, for example for keytype=RSA this would be + // PEM. Not able to use 'public' as name because it is reserved keyword. + bytes public_key = 1; +} diff --git a/pw_software_update/pw_software_update_protos/update_bundle.proto b/pw_software_update/pw_software_update_protos/update_bundle.proto new file mode 100644 index 000000000..d1d7a358a --- /dev/null +++ b/pw_software_update/pw_software_update_protos/update_bundle.proto @@ -0,0 +1,36 @@ +// Copyright 2021 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +syntax = "proto3"; + +package pw.software_update; + +import "tuf.proto"; + +message UpdateBundle { + optional SignedMetadata root_metadata = 1; + optional SignedMetadata timestamp_metadata = 2; + optional SignedMetadata snapshot_metadata = 3; + map targets_metadata = 4; + + // Map of target path to target payload bytes. + map target_payload = 5; +} + +// Update bundle metadata +// Designed to inform the update server what the device currently has in-place. +message Manifest { + optional Metadata snapshot_metadata = 1; + map targets_metadata = 2; +}