diff --git a/01-messaging.md b/01-messaging.md index 78def343b..9c1885121 100644 --- a/01-messaging.md +++ b/01-messaging.md @@ -259,11 +259,10 @@ The following convenience types are also defined: * `sciddir_or_pubkey`: either 9 or 33 bytes referencing or identifying a node, respectively * if the first byte is 0 or 1, then an 8-byte `short_channel_id` follows for a total of 9 bytes * 0 for the first byte indicates this refers to `node_id_1` in the `channel_announcement` for `short_channel_id` - * 1 for the first byte indicates this refers to `node_id_2` in the `channel_announcement` for `short_channel_id` - (see [BOLT #7](07-routing-gossip.md#the-channel_announcement-message) + * 1 for the first byte indicates this refers to `node_id_2` in the `channel_announcement` for `short_channel_id` (see [BOLT #7](07-routing-gossip.md#the-channel_announcement-message)) * if the first byte is 2 or 3, then the value is a 33-byte `point` * `bigsize`: a variable-length, unsigned integer similar to Bitcoin's CompactSize encoding, but big-endian. Described in [BigSize](#appendix-a-bigsize-test-vectors). -* `utf8`: a byte as part of a UTF-8 string. A writer MUST ensure an array of these is a valid UTF-8 string, a reader MAY reject any messages containing an array of these which is not a valid UTF-8 string. +* `utf8`: a byte as part of a UTF-8 string. A writer MUST ensure that an array of these is a valid UTF-8 string without characters in the unicode "Other" (C*) General Category. A reader MUST reject any messages containing an array of these which is not a valid UTF-8 string without characters in the unicode "Cc", "Cf", "Cs", or "Co" General Category and MAY reject if it contains characters in the Unicode "Cn" (unassigned) General Category. ## Setup Messages diff --git a/07-routing-gossip.md b/07-routing-gossip.md index d399237de..63ca2c994 100644 --- a/07-routing-gossip.md +++ b/07-routing-gossip.md @@ -216,6 +216,8 @@ The receiving node: - MUST ignore the message. - if there is an unknown even bit in the `features` field: - MUST NOT attempt to route messages through the channel. + - if the `features` field is NOT minimally-encoded: + - MUST ignore the message. - if the `short_channel_id`'s output does NOT correspond to a P2WSH (using `bitcoin_key_1` and `bitcoin_key_2`, as specified in [BOLT #3](03-transactions.md#funding-transaction-output)) OR the output is @@ -338,8 +340,8 @@ The origin node: graphs. - Note: the first byte of `rgb_color` is the red value, the second byte is the green value, and the last byte is the blue value. - - MUST set `alias` to a valid UTF-8 string, with any `alias` trailing-bytes - equal to 0. + - MUST set `alias` to a valid UTF-8 string without characters in the unicode + "Other" (C*) General Category, with any `alias` trailing-bytes equal to 0. - SHOULD fill `addresses` with an address descriptor for each public network address that expects incoming connections. - MUST set `addrlen` to the number of bytes in `addresses`. @@ -349,7 +351,7 @@ The origin node: - MUST NOT create an address descriptor with `port` equal to 0. - SHOULD ensure `ipv4_addr` AND `ipv6_addr` are routable addresses. - MUST set `features` according to [BOLT #9](09-features.md#assigned-features-flags) - - SHOULD set `flen` to the minimum length required to hold the `features` + - MUST set `flen` to the minimum length required to hold the `features` bits it sets. - SHOULD not announce a Tor v2 onion service. - MUST NOT announce more than one `type 5` DNS hostname. @@ -370,6 +372,11 @@ any future fields appended to the end): - Unless paying a [BOLT #11](11-payment-encoding.md) invoice which does not have the same bit(s) set, MUST NOT attempt to send payments _to_ the node. - MUST NOT route a payment _through_ the node. + - if `features` is NOT minimally-encoded: + - MUST ignore the message. + - if `alias` is NOT a valid UTF-8 string without characters in the unicode + "Cc", "Cf", "Cs", or "Co" General Category: + - MUST ignore the message. - SHOULD ignore the first `address descriptor` that does NOT match the types defined above. - if `addrlen` is insufficient to hold the address descriptors of the @@ -424,6 +431,42 @@ engines that support SQL or other dynamically interpreted querying languages. Don't be like the school of [Little Bobby Tables](https://xkcd.com/327/). +### Test vectors + +The following test vectors are `node_announcement`s with aliases that contain +illegal unicode characters. Implementations MUST ignore these announcements. + +The signature was created with the following private key: + +```code +priv=0x1111111111111111111111111111111111111111111111111111111111111111 +``` + +```json +[ + { + "name": "Alias containing a NULL (Cc) character", + "alias": "lightning\u0000rocks", + "announcement": "01013a3f3d28c538ae96c5c032e534fedea3e452261ebaea82952456c2a9f7477e7151575ce7e36f2f5b38bb27210c8fbdc72dcd92a99b3df47536ad61d8699cbb1c000067b64b00034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa0102036c696768746e696e6700726f636b7300000000000000000000000000000000000000" + }, + { + "name": "Alias containing a DEL (Cc) character", + "alias": "lightning\u007frocks", + "announcement": "01011ac8fe92da793fe0b1472616b6cb4346e746fe72d68c1865f79a5bc6ad371e824ce9c91b83b23a5a65eb6c6e07cd4bd84bec6892958d969559b6059424ac2894000067b64b00034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa0102036c696768746e696e677f726f636b7300000000000000000000000000000000000000" + }, + { + "name": "Alias containing a zero-width space (Cf)", + "alias": "lightning\u200brocks", + "announcement": "0101eb387795f9b453da150cd16b683595ecacc94f6b41d74e1908eef1b8782a6e606e8b9e073ba4fc7eccef5d450faa52e99582db9c620df3fa6f33598220a3b886000067b64b00034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa0102036c696768746e696e67e2808b726f636b730000000000000000000000000000000000" + }, + { + "name": "Alias containing a private use character (Co)", + "alias": "lightning\ue000rocks", + "announcement": "0101f3575e38f455655b2e54ea4df8b1745c13938db744d6607fc142cf5be2ce619326ffa6a3f48ac764c7d3d20055fc855f515b77b74c26451862732a8a1f39da1f000067b64b00034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa0102036c696768746e696e67ee8080726f636b730000000000000000000000000000000000" + } +] +``` + ## The `channel_update` Message After a channel has been initially announced, each side independently diff --git a/11-payment-encoding.md b/11-payment-encoding.md index ffd29a090..4ef828a9c 100644 --- a/11-payment-encoding.md +++ b/11-payment-encoding.md @@ -171,7 +171,8 @@ A writer: that will be given in return for payment. - MUST include either exactly one `d` or exactly one `h` field. - if `d` is included: - - MUST set `d` to a valid UTF-8 string. + - MUST set `d` to a valid UTF-8 string without characters in the unicode + "Other" (C*) General Category. - SHOULD use a complete description of the purpose of the payment. - if `h` is included: - MUST make the preimage of the hashed description in `h` available @@ -212,6 +213,8 @@ A reader: - MUST skip over `f` fields that use an unknown `version`. - MUST fail the payment if any field with fixed `data_length` (`p`, `h`, `s`, `n`) does not have the correct length (52, 52, 52, 53). - MUST fail the payment if neither a `d` field nor a `h` field is present, or if both are present. + - MUST fail the payment if the `d` field is not a valid UTF-8 string without characters in the unicode "Cc", "Cf", "Cs", or "Co" General Category. + - MAY fail the payment if the `d` field contains characters in the Unicode "Cn" (unassigned) General Category. - if the `9` field contains unknown _odd_ bits that are non-zero: - MUST ignore the bit. - if the `9` field contains unknown _even_ bits that are non-zero: diff --git a/12-offer-encoding.md b/12-offer-encoding.md index f5860cffb..261f1707c 100644 --- a/12-offer-encoding.md +++ b/12-offer-encoding.md @@ -249,7 +249,7 @@ A writer of an offer: - MUST specify `offer_amount` in the currency unit adjusted by the ISO 4217 exponent (e.g. USD cents). - MUST set `offer_description` to a complete description of the purpose - of the payment. + of the payment without characters in the unicode "Other" (C*) General Category. - otherwise: - MUST NOT set `offer_amount` - MUST NOT set `offer_currency` @@ -257,6 +257,7 @@ A writer of an offer: - MAY set `offer_metadata` for its own use. - if it supports bolt12 offer features: - MUST set `offer_features`.`features` to the bitmap of bolt12 features. + - MUST minimally-encode `offer_features`.`features`. - if the offer expires: - MUST set `offer_absolute_expiry` `seconds_from_epoch` to the number of seconds after midnight 1 January 1970, UTC that invoice_request should not be @@ -272,6 +273,7 @@ A writer of an offer: - MUST set `offer_issuer_id` to the node's public key to request the invoice from. - if it sets `offer_issuer`: - SHOULD set it to identify the issuer of the invoice clearly. + - MUST NOT use characters in the unicode "Other" (C*) General Category. - if it includes a domain name: - SHOULD begin it with either user@domain or domain - MAY follow with a space and more text @@ -292,12 +294,20 @@ A reader of an offer: - if `offer_features` contains unknown _even_ bits that are non-zero: - MUST NOT respond to the offer. - SHOULD indicate the unknown bit to the user. + - if `offer_features` is not minimally-encoded: + - MUST NOT respond to the offer. - if `offer_chains` is not set: - if the node does not accept bitcoin invoices: - MUST NOT respond to the offer - otherwise: (`offer_chains` is set): - if the node does not accept invoices for at least one of the `chains`: - MUST NOT respond to the offer + - if `offer_description` or `offer_issuer` contain characters in the unicode + "Cc", "Cf", "Cs", or "Co" General Category: + - MUST NOT respond to the offer + - if `offer_description` or `offer_issuer` contain characters in the unicode + "Cn" (unassigned) General Category: + - MAY NOT respond to the offer - if `offer_amount` is set and `offer_description` is not set: - MUST NOT respond to the offer. - if `offer_amount` is set and is not greater than zero: @@ -384,7 +394,6 @@ for [Signature Calculation](#signature-calculation). This ensures that merkle leaves are unguessable, allowing a future compact representation to hide fields while still allowing signature validation. - ## TLV Fields for `invoice_request` 1. `tlv_stream`: `invoice_request` @@ -496,6 +505,9 @@ The writer: (e.g. milli-satoshis for bitcoin) for `invreq_chain` (or for bitcoin, if there is no `invreq_chain`). - if it supports bolt12 invoice request features: - MUST set `invreq_features`.`features` to the bitmap of features. + - MUST minimally-encode `invreq_features`.`features`. + - if it includes `invreq_payer_note`: + - MUST NOT use characters in the unicode "Other" (C*) General Category. - if it received the offer from which it constructed this `invoice_request` using BIP 353 resolution: - MUST include `invreq_bip_353_name` with, - `name` set to the post-₿, pre-@ part of the BIP 353 HRN, @@ -508,6 +520,8 @@ The reader: - MUST ignore the bit. - if `invreq_features` contains unknown _even_ bits that are non-zero: - MUST reject the invoice request. + - if `invreq_features` is not minimally-encoded: + - MUST reject the invoice request. - MUST reject the invoice request if `signature` is not correct as detailed in [Signature Calculation](#signature-calculation) using the `invreq_payer_id`. - if `num_hops` is 0 in any `blinded_path` in `invreq_paths`: - MUST reject the invoice request. @@ -549,6 +563,11 @@ The reader: - MUST reject the invoice request if bitcoin is not a supported chain. - otherwise: - MUST reject the invoice request if `invreq_chain`.`chain` is not a supported chain. + - if `invreq_payer_note` is present: + - if it contains characters in the unicode "Cc", "Cf", "Cs", or "Co" General Category: + - MUST reject the invoice request. + - if it contains characters in the unicode "Cn" (unassigned) General Category: + - MAY reject the invoice request. - if `invreq_bip_353_name` is present: - MUST reject the invoice request if `name` or `domain` contain any bytes which are not `0`-`9`, `a`-`z`, `A`-`Z`, `-`, `_` or `.`. @@ -735,6 +754,8 @@ A writer of an invoice: - MUST set `invoice_node_id` to the final `blinded_node_id` on the path it received the invoice request - MUST specify exactly one signature TLV element: `signature`. - MUST set `sig` to the signature using `invoice_node_id` as described in [Signature Calculation](#signature-calculation). + - if it includes `invoice_features`: + - MUST minimally-encode `invoice_features`.`features`. - if it requires multiple parts to pay the invoice: - MUST set `invoice_features`.`features` bit `MPP/compulsory` - or if it allows multiple parts to pay the invoice: @@ -768,6 +789,8 @@ A reader of an invoice: - MUST ignore the bit. - if `invoice_features` contains unknown _even_ bits that are non-zero: - MUST reject the invoice. + - if `invoice_features` is not minimally-encoded: + - MUST reject the invoice. - if `invoice_relative_expiry` is present: - MUST reject the invoice if the current time since 1970-01-01 UTC is greater than `invoice_created_at` plus `seconds_from_creation`. - otherwise: @@ -856,7 +879,6 @@ a response to an invoice request, that field must have existed due to the invoice request requirements, and we also require it to be mirrored here. - # Invoice Errors Informative errors can be returned in an onion message `invoice_error`