Skip to content

Latest commit

 

History

History
599 lines (421 loc) · 35.3 KB

signing-spec.md

File metadata and controls

599 lines (421 loc) · 35.3 KB

Signing Parcels and Parcel Lists

This portion of the specification discusses the mechanics of signing parcel lists on invoices.

In the Invoice specification, there are fields for attaching cryptographic signatures. This specification describes the form and function of those fields.

The term Bindle (uppercase) refers to the package storage system. The term bindle (lowercase) means a package in the Bindle system.

Things NOT covered

  • Key management. Here, we talk about using asymmetric cryptography to sign lists of parcels, but we do not discuss how the public and private keys are to be managed.
  • Strengths and weaknesses of various signature algorithms. We supply here only a single Ed25519 implementation.

The General Idea

The basic idea of signing significant items is that by attaching a signature, we can support tooling that has the ability to verify that certain facts about a bindle remain unchanged over time.

Specifically, we want assurances of two things:

  1. That an invoice at a particular version has exactly a particular set of parcels.
  2. That each parcel has exactly the content that the signer intended.

For example, by signing a parcel's hash, we can in effect certify that an entity in possession of the signing key testifies that the parcel had this hash at the time in which the parcel was signed. That is an important attestation when combined with a few other things (like key trust), because it provides a foundation for making assertions like this:

Matt Butcher signed the hash for the parcel when he built it, and the hash hasn't changed. Therefore, the parcel is in the same condition it was when Matt Butcher built it.

Asymmetric cryptography is nice for this because a signer can distribute a public key and a signature, and that is enough information for someone to verify that the signature was generated by the signer's private key.

Signing and Roles

Signers of an invoice MUST have a role. The following roles are defined by this specification. Agents SHOULD initiate a warning and SHOULD initiate a failure if a user's expected role does not match the given role.

  • creator: Signer asserts that they are the ones who made this bindle
  • approver: Signer asserts that they have verified the contents of the bindle
  • proxy: Signer asserts that they are a consumer or waypoint for this bindle, and have no reason to distrust the bindle
  • host: Signer asserts that it has served as a Bindle host for this content

No invoice can be signed twice by the same key. For example, a key cannot be used to sign both as creator and as host. Nor are there any cases where a key is permitted to sign twice with the same role.

The Creator Role

The creator signature MUST be on any invoice that is compliant with this system. There MAY be multiple creators on an invoice. A creator MUST NOT sign the same invoice with the same key multiple times. The Bindle server MUST reject an invoice that is not signed by a creator. (In other words, all bindles MUST be signed by a creator key before they can be hosted.) When a new bindle is submitted, a Bindle server MUST reject an invoice that is signed by a creator's key for which the server does not have an entry in its keyring. In other words, the server MUST have the keys for every creator whose Bindle it accepts to host. A bindle server MUST NOT sign a bindle with its host key if it does not have the key of the creator in its keyring. This does not necessarily preclude a "caching proxy", where the proxy is repeating a Bindle that has been signed by another set of creator and host keys.

A caching proxy is a Bindle server that takes a user's request for a bindle, finds that bindle remotely, and then caches that bindle's content locally so that it may re-serve that content at a later date. Such servers MAY sign with a proxy key.

A client SHOULD reject an invoice that is not signed by a known key with the creator or approver role. A non-normative recommendation would be that a client ought to reject any bindle where neither a creator's nor a approver's signature could be verified.

The Approver Role

The approver role describes a signer who asserts that the signer has employed a method of assessing whether the bindle is correct.

Examples of approvers might include:

  • A developer who reviews the code and build tools for the bindle's parcels
  • A security scanner that runs an audit of the bindle and parcels
  • A security researcher who performs a security audit and deems the bindle and parcels safe.

The approver role is specific to the security context. This signer is not deciding whether text content is editorially correct or that an image looks good. The signer is asserting that the security profile of the bindle is deemed trustworthy. That is, a vulnerability scanner is asserting, upon signature, that it detected no vulnerabilities in the bindle.

An underlying assumption of the present model is that keys with the approver role will be vetted more carefully before inclusion in the keyring. End users in particular should be careful to only include well-known entities in their approver keyring.

Verification may form a trust proxy. That is, a client may decide that if the creator is unknown, the bindle can still be trusted if one or more of the approver keys is known.

The Host role

The host role denotes that the signer is the Bindle server that accepted the invoice from the creator.

Bindle servers MUST add a host entry to a bindle upon receiving the bindle from a client and verifying the creator key. A bindle server MUST NOT sign the same invoice more than once with the same key. Clients MAY reject invoices that are signed by unknown hosts.

The Proxy Role

Proxy signatures are designed for provenance more than security. When a non-creator pushes a bindle to a Bindle server, the non-creator SHOULD sign the invoice with a proxy signature.

Examples of proxy signers:

  • CI systems
  • Users who transfer bindles from one Bindle server to another
  • Import/export tools
  • Proxy servers

While this is implicit in the definitions, we should make it explicit that a Bindle server can use the same key to sign some invoices as a host (for bindles it hosts) and sign others as a proxy (for pass-through and cache features). However, it cannot sign the same invoice with the same key acting as both a host and proxy. In each case, the key must be marked for the appropriate role.

Signing and Timestamps

The date and time of a signature can be an important piece of information for auditing.

Both invoice and parcel signatures require an at field with a UNIX timestamp expressed as an unsigned 64-bit integer with no leading zeros.

Time stamps MUST be greater than 0. It is nonsensical to have a signature older than the the specification. For the sake of consistency, though, a 0 value is allowed in the formatting. However, implementations MAY reject any entries whose timestamps predate Sept. 1, 2020.

Since signature blocks are not primarily designed for human consumption, an implementation should prioritize simplicity and consistency over readability. The UNIX timestamp offers this:

  • It is well defined
  • It is adopted broadly
  • It is an unambiguous format that can easily be represented, serialized, and parsed
  • It is accurate enough for the problem at hand

Longer textual formats are subject to parsing and serialization ambiguities, as well in quirks of implementation across languages.

Signing on the Invoice

Signatures are included in the invoice.toml for a Bindle. Signing an invoice is an append-only operation. Once a signature has been added, that signature MUST NOT be modified and MUST NOT be deleted. This specification provides a number of caveats for handling key rotation. Key rotation does not warrant or allow modifying signatures.

The signature does not need to sign the entire content of the invoice. Rather, it needs to sign particular relationships. For example, the list of parcels that belong to a bindle is both definitive and immutable. As such, the list of parcel hashes should be signed to bind an exact parcel to a bindle. Other pieces of information should also be signed, such as the name and version of a bindle. The exhaustive list (and the format) are discussed below.

To ensure that no other parts of an invoice have been modified, a host MAY take steps to verify the continued integrity of the invoice.toml and SHOULD encrypt all traffic between itself and clients.

Signatures on an invoice look like this:

bindleVersion = "v1.0.0"

[bindle]
name = "mybindle"
version = "0.1.0"
authors = ["Matt Butcher <matt.butcher@microsoft.com>"]
description = "My first bindle"

[[signature]]
by = "Matt Butcher <matt.butcher@example.com>"
signature = "ddd237895ac..."
key = "1c44..."
role = "creator"
at = 1611960337

[[parcel]]
label.sha256 = "e1706ab0a39ac88094b6d54a3f5cdba41fe5a901"
label.mediaType = "text/html"
label.name = "myparcel.html"

[[parcel]]
label.sha256 = "098fa798779ac88094b6d54a3f5cdba41fe5a901"
label.name = "style.css"
label.mediaType = "text/css"

[[parcel]]
label.sha256 = "5b992e90b71d5fadab3cd3777230ef370df75f5b"
label.mediaType = "application/x-javascript"
label.name = "foo.js"
label.size = 248098

This format does not change with groups or conditions.

The signature is computed by concatenating the following pieces of data together in a line-separated (\n) UTF-8 string: by, name, version, role, at and the label.sha256 of each parcel:

Matt Butcher <matt.butcher@example.com>
mybindle
0.1.0
creator
1611960337
~
e1706ab0a39ac88094b6d54a3f5cdba41fe5a901
098fa798779ac88094b6d54a3f5cdba41fe5a901
5b992e90b71d5fadab3cd3777230ef370df75f5b

Note that the sequence \n~\n is used as a separator to prevent an attempt to forge a hash using another field.

Verifying

To verify, it is assumed that the client has access to a keyring that contains one or more public keys.

Verification of an invoice includes the following steps:

  1. Load the invoice
  2. Extract the signature block from the invoice
  3. Reconstruct the cleartext block following the signing rules
  4. For each signature block a. Extract the public key b. Verify that the key has not already been used in another signature block - If a key is used to sign the same invoice multiple times, the implementation SHOULD fail c. Verify the signature using the public key and the cleartext data - If verification fails for a known signer, the application MUST fail - If the verification fails for an unknown signer (whose key does not exist in the keyrings), the application SHOULD emit a warning and MAY fail. Consider, though, that failing could allow an attack to forge known-bad signatures as a denial of service attack. d. Locate the key in the keyring - If the key is not located, this is not an error
  5. Apply a key trust strategy (See "Strategies of Key Trust" below)
    • At minimum, the strategy should be that the creator signature is signed with a known key (Strategy 1).
    • For use on public bindle servers, allowing the creator or approver strategy (Strategy 2) is preferred.

Keyrings

A keyring is an annotated list of (public) keys that can be used for verifying signatures in a bindle.

A private key MUST NOT be stored in a keyring. Keyring data is considered non-secret (and thus a keyring could be checked into a VCS system or published on the Internet in some cases, and not as a result have integrity compromised).

The keyring format is expressed as TOML here:

version = "1.0"

[[key]]
label = "Matt Butcher <technosophos@example.com>"
roles = ["creator", "approver"]
key = "aa453q4..."
labelSignature = "dsaff678..."

[[key]]
label = "Brigade pipeline at builder.example.com"
roles = ["proxy"]
key = "bb453q4..."
labelSignature = "dsaff678..."

[[key]]
label = "https://bindle.example.com"
roles = ["host"]
key = "cc453q4..."
labelSignature = "dsaff678..."

Fields on the [[key]] object:

  • label: A human-readable label that hints what this key is for
  • roles: A list of roles that the user has granted to the key
  • key: The base64-encoded public key for this label
  • labelSignature: A signature block for the label, to assert that the label is the same one that was intended by the key creator (optional, may be removed)

Reading Signatures as Provenance

# This identity asserts that it has created the bindle
[[signature]]
by = "Matt Butcher <matt.butcher@example.com>"
signature = "ddd237895ac..."
key = "1c44..."
role = "creator"
at = 1611960337

# This identity asserts that it has somehow proxied the bindle.
# In this case, it is a CI action that pushed the bindle to a host
[[signature]]
by = "GitHub Action [https://github.com/exammple.com/hello_repo]"
signature = "3dd237895ac..."
key = "3c44..."
role = "proxy"
at = 1611960347

# This identity asserts that it has hosted the bindle
[[signature]]
by = "Bindle Server [https://bindle.example.com]"
signature = "2dd237895ac..."
key = "2c44..."
role = "host"
at = 1611960357

Because of the timestamps, we can reconstruct the timeline and see that the key was first signed by the creator, then signed by the proxy, and finally signed by the host.

Strategies of Key Trust

This section is non-normative, describing how implementations MAY choose to behave.

A bindle may be signed by any number of keys in any number of roles. During verification, which of these keys must be verified?

The simplest configuration of Bindle would require that the creator key be present in the keyring, and the content is then verified against this key's signature. All other keys MAY be verified.

This section provides alternative trust strategies that allow different degrees of verification. Implementations may match their validation practices to the security needs of their environment.

Five strategies are discussed here. This is not an exhaustive set, but it illustrates the possibilities.

Strategy 1: Creative Integrity

In this model, the creator signature is the only one we care about in verification. It is as if we are saying, "If the creator says the package I have is the right one, that is all the evidence I need."

Strategy 2: Authoritative Integrity

This case might be considered weaker than the above, but it illustrates a different way to delegate according to which entity is considered the stronger authority. In this case, we say that if the creator or an approver asserts that this package is correct, then we accept it.

This setup is useful for a few configurations:

Public package repositories: In this case, there may be tens of thousands of creators. But say that a designated entity could analyze the packages and determine their safety. In that case, a user agent might say "I will accept any package that has been signed by this trusted analyzer."

Internal package repository: In this case, an enterprise may make a stronger claim: "Whether you can use this package does not depend on whether the creator is trusted, but whether the package is marked as trusted by our internal approver."

Strategy 3: Multiple Attestation

In this strategy, at least two roles must be verified. The object of this configuration is double-checking for a compromise.

Here are a few scenarios for multiple attestation:

Creator and CI Pipeline: Ostensibly, a CI system will build the same package using the same tooling that the creator used. Assuming the CI signs its artifacts with the proxy role, one could require that both creator and proxy signatures must be present and be verified. This way, if the creator's system is compromised or misconfigured, this would show up in the form of a clash with the proxy signature. While it doesn't identify whether the proxy or the creator was compromised, it shows up as a clash between two distinct keys--and therefore serves as a signpost for where the problem may be.

Creator and Host: A similar pairing can be done between the creator role and the host role. In this case, comparing between the host and creator roles identifies any case where the package was compromised during or after upload to the server.

Creator and approver: This pairing is a step beyond the "Authoritative Integrity" section above, as it requires that both a creator and a approver can be verified. In other words, for a bindle to be verified, the creator has to certify that they created it, and the approver has to certify that the bindle has been audited.

From here, we could extrapolate to various other combinatorics (e.g. signer, host, and approver must all have verified signatures). But the core idea remains: a conjunction of verifications provides more security than a disjunction.

Strategy 4: Greedy Verification

This model is the best default model. In it, there is an obligation to verify the creator signature, but verifying every other signature in the invoice SHOULD be attempted.

In this model:

  • If the creator signature fails verification, the verification process should end with an error
  • For each signature, its public key should be used to verify the signature. If this fails, the verification should end with an error.
  • For each signature, its public key should be checked against the keyring. If the signature is missing, a warning should be emitted

The result is that every signature is partially tested, at least one must be fully tested, and any that cannot be fully tested are reported to the user.

(Bindle currently implements this strategy, but in the future, strategy will be configurable)

Strategy 5: Exhaustive Verification

In this strategy, every signature on the invoice must be verified.

Therefore, if an invoice has ten signatures spread across all four roles, every single signature must be verified. Any unknown keys or mismatched signatures will cause failure.

This is a strong assertion that will lead to fragile process (virtuously, in some cases). It is designed for cases where every single step must be secured. It will surface not just tampered packages, but also tampered process. While not infallible, it can give an early and decisive warning if a package crossed the wrong security boundary. For example, if a package is signed by an unknown host key, then this package has been hosted on a server outside the chain of trust. While this level of scrutiny is not desirable on, say, a public Bindle registry, it may be invaluable to closed and air-gapped networks where the presence of an unknown signature may warn of a misconfiguration.

Strategy 6: Multiple Attestation Greedy

The same as the Multiple Attestation strategy with the additional requirement that verifying every other signature in the invoice SHOULD be attempted, similar to Greedy.

For example, if validating creator and approver under normal Multiple Attestation, only signatures with those roles would be validated. Under Multiple Attestation, all other roles would also be validated

Yanking Bindles

An invoice has the field yanked available as a top-level field. However, this field is not present in the signed metadata. The reason for this is that a yanked package is not, in virtue of its yanking, invalid. So simply yanking a bindle MUST NOT result in invalidating the bindle. (The reason a yank does not invalidate a Bindle is that the yank merely warns that the authors no longer wish for you to use the bindle, not that the bindle necessarily has a problem.)

Consequently, when a bindle is yanked, the invoice MUST be updated in two ways:

  • The top-level yanked field MUST be set to true
  • The host key MUST generate a yanked_signature composed by signing the following block of data:
Matt Butcher <matt.butcher@example.com>
mybindle
0.1.0
host
1611960337
yanked
~
A security flaw was found. See CVE-1234 for details.

This differs from the regular signature block in four important ways:

  • The only role that is allowed to sign in this way is the host role
  • The timestamp is the time at which the host marked this bindle as yanked
  • The word yanked appears below the timestamp. This is a trivial guard against an attack that attempts to repurpose a parcel-less signature as a yank block.
  • After the ~ divider, the optional yanked_reason is included. If a yanked_reason is provided on the invoice, it MUST be included in the signature block to prevent tampering.

To verify a yanked_signature, an agent:

  • MUST verify that the host key used to sign is in the agent's keyring
    • An agent MAY refuse to treat a bindle as yanked if the key is not known
    • An agent SHOULD notify the user if a bindle is yanked, but the yanking host key is not known
  • MUST verify that the signature is valid (using the same formula described for regular signature validation).
  • SHOULD verify that the timestamp for yanking is not the same as the signature block's at timestamp.
    • This is a trivial protection against attempts to forge a yank block.
  • SHOULD require that the host key used to yank is also the same host key originally used to sign
    • This is complicated by host key rotation. Our recommendation is that on host key rotation, all packages should be re-signed using the new host key so that it is always clear who the host authority is.

The format of the yanked_signature is the same as the format of a regular signature:

bindleVersion = "1.0.0"
yanked = true

[[yanked_signature]]
by = "Matt Butcher <matt.butcher@example.com>"
signature = "ddd237895ac..."
key = "1c44..."
role = "host"
at = 1611960337

Note that this strategy does not prevent a key from being used to generate a known-bad signature so that the validation fails.

Known Issues with Yank Signing

The current model does not provide a way to say "this package should never be trusted again" except for generating known-bad signatures.

Likewise, while signing with host keys indicates that the host has yanked the package, there is no clear way to indicate the creator's intent, or a verifier's stance. The reason for this is that yanking is a host-specific operation, and does not have to do directly with creator intent. (In other words, the creator is not the authority on whether a bindle is yanked. The host is.)

A compromised host could yank all packages, which may have dire initial consequences. However, these consequences are probably the correct consequences when a compromise happens, as the result is a denial of service from the host to the agent.

A yanked field and the yankedSignature could both be removed by a malicious host, which would allow a rollback attack. There is currently not a mitigation from this. (Compromised hosts can also remove regular signature blocks, effectively rendering a signed bindle unsigned.)

As with regular signature blocks, yankedSignature is append-only. When a host rotates its keys, it SHOULD append a new yankedSignature block, but it MUST NOT remove the old yankedSignature block.

Possible Alternatives to Yank Signing

The yanked field could be included in the main signing metadata. This would create a strong yank under which the yank would invalidate all signatures.

The main flaw with this route is that it makes a strong claim about what yanked means. In this case, yanked means "it is never secure to use this package", which may be true in some cases, but not all.

Another issue with this approach is that a yanked bindle's non-host signatures would all be initially invalidated by the yank operation, even though the actual content of the package has not changed. This would require verifiers and creators to go re-sign packages again after the yanked field was toggled to true. Thus, on yank, a bindle would become unusable until the signers re-signed. That was not the intent of the yanked field or the yanking operation.

Threat Model

This section describes our threat model in applying signatures. Our inspiration has been TUF. However, Bindle's problem space is slightly different:

  • Bindle is not concerned with updating a package. The identifier (name plus version) is "static" and must always point to the same artifact.
  • Bindle is concerned with more than storage and retrieval.

Likewise, Bindle is distinct from in-toto. While in-toto focuses on the assembly of the package (and how to attest and verify the steps of creating the package), Bindle's security model involves attesting and verifying the produced package at specific stages. It may be possible to map out Bindle's model using an in-toto static layout.

Bindle's signing model is designed to provide a way for multiple entities (in different roles) to attach attestations to an immutable set of objects. Note that Bindle's security model is complementary to both TUF and in-toto: All three of these technologies could be used in conjunction.

We assume that:

  • No single key holder can be assumed to be trustworthy
    • A creator is generally an authority on what they wish to produce, but is not necessarily to be trusted to produce non-malicious bindles
    • An approver, likewise, may produce results that are incomplete or potentially malicious
    • A proxy or host may be malicious
  • An attacker can act as a man-in-the-middle (MITM) via hijacking or proxying. Therefore, the security model must assume a potential MITM.
  • If an attack can compromise enough keys, the best that can be done by this spec is to limit the distribution of compromised bindles
  • A malicious signer can cause a package's trust to be doubted (e.g. denial of service), but it should not be able to make a doubted package's trust accepted.
    • That is, if other signatures are invalid, a malicious signature should not be able to override that invalidation
    • But as a weakness in the system, if a malicious signer forges a bad signature, that signature may result in an un-compromised package becoming untrusted for any user who has the malicious signer's signature in their keyring. (For example, an attacker with access to the invoice could attach a signature with a known public key and a garbage signature block, and anything that validated the signatures would fail.)
    • In highly secure systems, a malicious signer may be able to deny service merely by attaching a bad signature to an invoice (e.g. in a system that treats any verification failure -- on known or unknown keys -- as a failure condition). This, however, may be a valid condition, as it indicates that an attacker tampered with the invoice.

The Creator

A creator signature is intended to indicate that the entity that created the bindle believes the bindle to be a correct representation of their intent. A creator may intend to distribute malicious software. (That is, the creator may be malicious, or may be unaware that the software has been compromised already.)

Proxy and approver signatures may help mitigate this. For example, an approver signature indicates that the approver believes the package to be safe. A proxy may indicate that the package was rebuilt and found to be the same.

The Approver

An approver signature indicates that the given signer believes the package to be safe. However, an approver may be acting maliciously. Note that this is only damaging if the creator's package is also compromised. That is, for a malicious approval to be dangerous, the package has to be compromised. Depending on the Key Trust Strategy, both the creator and approver would have to be malicious (or tricked) before this becomes a problem.

The Proxy

A proxy key ought not be given high trust in most cases. It is intended to function as a trace that a bindle passed through its control. It is better viewed as a ledger entry for reconstructing the provenance of a bindle.

The Host

A host signature is used to verify that the host that accepted the upload of the bindle was a trusted host. This affords an opportunity for stricter trust, in which only known trustworthy hosts are allowed to provide bindles. Given the distributed nature of Bindle, this means that an aggregation point (P, a proxy role) can pull in bindles from multiple hosts (H1, H2, H3). And a client may choose to only trust bindles that come from a trusted host (e.g. H1, but not H2 or H3).

Resistance Against Well-known Attacks

Some sorts of attacks are well-known. This describes how Bindle attempts to minimize, thwart, or prevent such attacks.

Intentionally Malicious Creator

An intentionally malicious creator is one who pushes bindles into a Bindle server with the express intention of distributing malware. Such actors are often difficult to detect. Bindle offers several mitigations against this sort of attack:

  • Bindle encourages a trust model that does not use packages created by an untrusted user. In Bindle, trust is enacted on the agent's side by adding a signer's key to the keyring.
  • Bindle provides an approver role whose intent is to allow a third-party auditor to demarcate which bindles the auditor believes to be trustworthy. Again, trust in an approver is enacted by adding the approver's key to the agent keyring.
  • If a creator or package is determined to be malicious (or just have a security hole), a host can yank that package, forcing agents to explicitly accept the risk of using that package.

Freeze and Rollback Attacks

A freeze attack occurs when an attacker can prevent a newer version of a package from taking precedence. A rollback attack occurs when an attacker can cause a newer version to be rolled back to a known-bad prior version.

Bindle does not have an innate concept of upgrades, and so prima facie would not have these problems. That is, bindle example/1.2.3 is not "upgraded" by Bindle to example/1.2.4. Bindle sees those as two entirely separate packages. However, we know that in practice, Bindle will be used by systems that perform updates of bindles from one version to the next. For that reason, Bindle employs some lower-level tooling to prevent certain sorts of freeze and rollback attacks, but other variants must be addressed at a higher level.

To prevent yank-based freeze/rollback attacks, yanked_signatures require that a host sign all yanked bindles, but in a way that does not invalidate the content signatures. This protects against most forms of freeze/rollback attacks in that (depending on the signature verification strategy) multiple keys must be compromised before a freeze/rollback can work.

However, at the time of this writing a compromised host key could mark a release as yanked and encourage agents to roll back to previous versions. This could result in a rollback attack to a vulnerable version. One potential work-around would be to not roll back unless the creator key was also used to sign the yank. However, this would rule out host-only yanks, which we view as necessary to prevent bad-intentioned creators from blocking yanks.

Note that even in such an attack, the compromised host cannot alter a bindle's content without invalidating the other signatures.

A fully compromised Bindle server is vulnerable to a freeze attack for the obvious reason that the attacker would control all avenues for publishing a Bindle via that host.

A proxy could perpetrate something like a freeze attack if an implementation's only strategy for checking for an update is to contact the proxy. Then a proxy can effectively fail to fetch a bindle, and consequently cause a freeze. Note, though, that this is a desirable effect of a system such as Bindle, in which an internal proxy may only have a subset of the packages available on the open web. Consequently, mitigation of this issue is left to higher-level implementations that may specify that when they get a "new version" (which is a discrete bindle from the "old version"), it follows a strategy proper to its usage.

Generating a Known-invalid Signature

This section is non-normative and may be removed.

In the case where an existing package is discovered to have a flaw that should prevent its verification, it is possible (though not always recommended, and never required) to generate an intentionally bad signature to force a verification failure.

The recommended way of doing this is to include the INVALID string inside of the hash contents after the timestamp. This makes it possible for an agent to reconstruct the signature and determine whether the signature was intentionally invalidated.

Matt Butcher <matt.butcher@example.com>
mybindle
0.1.0
creator
1611960337
INVALID
~
e1706ab0a39ac88094b6d54a3f5cdba41fe5a901
098fa798779ac88094b6d54a3f5cdba41fe5a901
5b992e90b71d5fadab3cd3777230ef370df75f5b

Note that simply generating an invalid signature does not necessarily mean that agents will respect this signature. An implementation may only mind invalid signatures on keys that are in its keyring or that are in a certain role.

Key Rotation

Bindle makes no assumptions about the frequency of key rotation. However, there are a few non-normative recommendations:

  • If a host key is rotated, all packages SHOULD be re-signed by the new host key.
    • For a properly configured Bindle server, this does not introduce an opportunity for an attacker to modify packages because the creator and all proxy and approver signatures remain unaltered, and any attempt to modify the package will invalidate those signatures
  • When a creator rotates keys, and the cause is NOT compromise, the user SHOULD re-sign existing bindles using the new key and the approver role. The original creator signature SHOULD NOT be altered in any way.
  • When an approver rotates keys, the approver SHOULD sign approved bindles with the new key. The old signature MUST NOT be removed.
  • When a proxy key is rotated, the proxy MAY sign previously signed bindles with the new key. However, because proxy signatures are considered to be temporal markers, this is entirely optional.
    • Old proxy key signatures MUST NOT be removed

If a host key is compromised and the window of time of compromise is known, the host SHOULD re-evaluate all packages marked as yanked during the compromise window. If the window of time is not known, then a thorough re-evaluation of yanked packages should take place.

If a creator key is compromised, a host SHOULD mark all packages signed by that key as yanked. If the compromise's window of time is known, a host MAY choose instead to yank only packages signed during that compromise window.

If a proxy or approver key is compromised, a host SHOULD remove all signature blocks made using that key. If a compromise's window of time is known, a host MAY choose instead to remove that signature from only the packages signed during that window.

If at any point the number of trusted signatures on a package is less than one, that package should be deemed untrusted, and appropriate measures taken (including potentially deleting that bindle from the repository). Likewise, if the only trusted key is a proxy key, this may be considered insufficient to warrant full trust, and similar measures may be taken. This security exception is the only case in this specification were outright deletion of a package is condoned.

In all of these cases, note that timestamps used inside of signature blocks from compromised keys should not be trusted. Timestamps from the system or from other signatures may serve as better points of trust.

Questions

Why Don't You Just Hash The Document?

A: Because TOML (and most on-disk formats) can be expressed in ways that are subtly different. Whitespace, quotation marks, and other formatting changes can render the signature ineffective.

Instead of inventing another format or using something like Canonical JSON (with all its quirks), we took a semantic approach: What are the pieces of data that we actually need to protect, and can we handle just those?