domain separation, remove CID and local storage

This commit is contained in:
Yusef Napora
2019-10-24 11:12:17 -04:00
parent 59f660b55d
commit b8f1c5ee0b

View File

@@ -20,6 +20,27 @@ would be nice to have an all-purpose data container that includes a signature of
the data, so we can verify that the data came from a specific peer and that it hasn't
been tampered with.
## Domain Separation
Signatures can be used for a variety of purposes, and a signature made for a
specific purpose MUST NOT be considered valid for a different purpose.
Without this property, an attacker could convince a peer to sign a paylod in one
context and present it as valid in another, for example, presenting a signed
address record as a pubsub message.
We separate signatures into "domains" by prefixing the data to be signed with a
string unique to each domain. This string is not contained within the payload or
the outer envelope structure. Instead, each libp2p subystem that makes use of
signed envelopes will provide their own domain string when constructing the
envelope, and again when validating the envelope. If the domain string used to
validate is different from the one used to sign, the signature validation will
fail.
Domain strings may be any valid UTF-8 string, but MUST NOT contain the `:`
character (UTF-8 code point `0x3A`), as this is used to separate the domain
string from the content when signing.
## Wire Format
Since we already have a [protobuf definition for public keys][peer-id-spec], we
@@ -29,10 +50,8 @@ can use protobuf for this as well and easily embed the key in the envelope:
```protobuf
message SignedEnvelope {
PublicKey publicKey = 1; // see peer id spec for definition
string purpose = 2; // arbitrary user-defined string for context
bytes cid = 3; // CIDv1 of contents
bytes contents = 4; // payload
bytes signature = 5; // signature of purpose + cid + contents
bytes contents = 2; // payload
bytes signature = 3; // signature of domain string + contents
}
```
@@ -40,27 +59,13 @@ The `publicKey` field contains the public key whose secret counterpart was used
to sign the message. This MUST be consistent with the peer id of the signing
peer, as the recipient will derive the peer id of the signer from this key.
The `purpose` field is an aribitrary string that can be used to give some hint
as to the contents. For example, if `contents` contains a serialized
`AddressState` record, `purpose` might contain the string `"AddressState"`. The
contents of the ``purpose`` field are signed alongside `contents` to prevent
tampering, and may be empty if desired.
The `cid` field contains a version 1 [CID][cid] (content id) that corresponds to
the `content` field. It's used for retrieving messages from [local
storage](#local-storage-of-signed-envelopes), and the embedded multicodec also
gives a hint as to the data type of the `contents`. If the user does not specify
a multicodec when constructing the envelope, the default will be
[`raw`](https://github.com/multiformats/multicodec/blob/master/table.csv#L34)
for raw binary.
## Signature Production / Verification
When signing, a peer will prepare a buffer by concatenating the following:
- The string `"libp2p-signed-envelope:"`, encoded as UTF-8
- The `purpose` field, encoded as UTF-8
- The `cid` field
- The [domain separation string](#domain-separation), encoded as UTF-8
- The UTF-8 encoded `:` character
- The `contents` field
Then they will sign the buffer according to the rules in the [peer id
@@ -70,25 +75,5 @@ To verify, a peer will "inflate" the `publicKey` into a domain object that can
verify signatures, prepare a buffer as above and verify the `signature` field
against it.
## Local Storage of Signed Envelopes
Signed envelopes can be used for ephemeral data, but we may also want to persist
them for a while and / or make previously recieved envelopes accesible to
various libp2p modules.
For example, if the envelope contains an [address record][addr-records-rfc],
those records might be used to populate a peer store with self-certified
records. Rather than requiring the peer store to persist the full envelope, we
could have a separate "envelope storage" service that keeps signed messages
around for future reference.
The peer store can then just store the `cid` alongside a flag that indicates
that the address came from a trusted source. If we're using a persistent peer
store and the process restarts, we can look up the stored `cid` in the envelope
storage and verify the signature again.
If we decide to build this, the storage service should have some kind of garbage
collection / TTL scheme to avoid unbounded growth.
[addr-records-rfc]: ./0003-address-records.md
[peer-id-spec]: ../peer-ids/peer-ids.md