From b8f1c5ee0b3f025bc8d459144121ec0efafd7e66 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Thu, 24 Oct 2019 11:12:17 -0400 Subject: [PATCH] domain separation, remove CID and local storage --- RFC/0002-signed-envelopes.md | 65 ++++++++++++++---------------------- 1 file changed, 25 insertions(+), 40 deletions(-) diff --git a/RFC/0002-signed-envelopes.md b/RFC/0002-signed-envelopes.md index 7a1bfcb..e3d8165 100644 --- a/RFC/0002-signed-envelopes.md +++ b/RFC/0002-signed-envelopes.md @@ -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