lsd0013

LSD0013: The donau:// scheme
Log | Files | Refs

commit ce301575122938ecc3c99570c954193efbbaf978
parent ae7366d9645d8a0dae30202728ee9ce117ea6e30
Author: Christian Grothoff <christian@grothoff.org>
Date:   Tue, 21 Oct 2025 21:40:46 +0200

major edits of English, consistency fixes, indentation fixes, clarifications, formatting/bcp14, etc.

Diffstat:
Mdraft-donau.xml | 689+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Mdraft-grothoff-donau-01.xml | 671++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
2 files changed, 771 insertions(+), 589 deletions(-)

diff --git a/draft-donau.xml b/draft-donau.xml @@ -20,7 +20,7 @@ <?rfc subcompact="no" ?> <rfc category="info" - docName="draft-donau-01" + docName="draft-grothoff-donau-01" ipr="trust200902"> <!-- FIXME ipr is copied from lsd0001, need to be updated --> <front> @@ -56,7 +56,7 @@ </address> </author> - + <author fullname="Bohdan Potuzhnyi" initials="B.P." surname="Potuzhnyi"> <organization>Bern University of Applied Sciences</organization> <address> @@ -71,7 +71,7 @@ </address> </author> - + <author fullname="Florian Dold" initials="F.D." surname="Dold"> <organization>Taler Systems AG</organization> <address> @@ -86,8 +86,8 @@ </address> </author> - - <date day="17" month="October" year="2025" /> + + <date day="21" month="October" year="2025" /> <!-- Meta-data Declarations --> <area>General</area> @@ -111,7 +111,7 @@ sum of donations a taxpayer made to recognized charities over a year. Donors would submit 'donau' URLs (or QR codes with 'donau' URLs) to tax authorities to have their donations - recognized by the tax authority as tax-deductable + recognized by the tax authority as tax-deductible expenditures. The application logic to verify the validity of the donation is triggered by 'donau' URIs. The validator application would then typically confirm to the tax official @@ -119,7 +119,7 @@ total amount donated as well as the taxpayer identification number and the year of the donation. Multiple URIs could be submitted per donor, and the application can correctly - determine which submissions are cummulative and which ones are + determine which submissions are cumulative and which ones are redundant. </t> @@ -133,59 +133,84 @@ protocols could be developed in the future and still yield compatible 'donau' URIs as the URI scheme is reasonably generic. </t> - + <t> + The validation tool will be registered for all donau:// URIs. + Since each taxation authority will typically use a different + domain, it will not be feasible to encode all the + domains of tax authorities servers inside the validation tool. + Hence a new URI scheme is needed that will trigger the validation + tool for any domain name. + </t> </abstract> </front> - <middle> +<middle> <section anchor="introduction" title="Introduction"> <t> - This document defines the 'donau' Uniform Resource Identifier (URI) <xref target="RFC3986" /> scheme - for triggering interactions with Donau validators. + This document defines the 'donau' Uniform Resource Identifier (URI) + <xref target="RFC3986" /> scheme for triggering interactions with + Donau validators. </t> <section title="Objective"> -<t> - A 'donau' URI always instructs a Donau validator to perform the - validation of a Donau donation statement. - A 'donau' URI consists of the reference to the authority - that signed the statement, an identifier for the specific taxpayer, - the year of the donation, a salt and optional parameters. - Optional parameters include the amount donated by the - taxpayer and the signature of the Donau donation statement. -</t> + <t> + A 'donau' URI always instructs a Donau validator to perform the + validation of a Donau donation statement. + A 'donau' URI consists of the reference to the authority + that signed the statement, an identifier for the specific taxpayer, + the year of the donation, a salt and optional parameters. + Optional parameters include the total amount donated by the + taxpayer and the signature of the Donau donation statement. + </t> + <t> + This specification is based on the Bachelor Thesis of + Casaburi and Matya <xref target="BaThesis" /> presenting the + solution and the first implementation of a Donau system. + </t> </section> + + <section title="Requirements Language"> -<t> - The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", - "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and - "OPTIONAL" in this document are to be interpreted as described in BCP 14 - <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, - they appear in all capitals, as shown here. -</t> + <t> + The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and + "OPTIONAL" in this document are to be interpreted as described in BCP 14 + <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, + they appear in all capitals, as shown here. + </t> </section> </section> <section anchor="syntax" - title="Syntax of a 'donau' URI"> + title="Syntax of a 'donau' URI"> <t> This document uses the Augmented Backus-Naur Form (ABNF) of <xref target="RFC5234"/>. </t> <figure> <artwork type="abnf"><![CDATA[ ; Scheme and high-level structure - scheme = "donau://" / "DONAU://" / "donau+http://" / "DONAU+HTTP://" - donau-URI = scheme base "/" year "/" taxid-enc "/" salt - [ "?" [ "total=" amount "&sig=" algo ":" signature ] ] + scheme = "donau" / "DONAU" / "donau+http" / "DONAU+HTTP" + donau-URI = scheme "://" base "?" year-param "&" taxid-param "&" salt-param + ("&" total-param "&" sig-param)? ; The base is the HTTP(S) origin plus optional path segments that ; identify the Donau REST API deployment. Everything before the last ; three path segments (year, taxid-enc, salt) is part of the base. base = 1*( ALPHA / DIGIT / "-" / "." / ":" / "/" / "_" ) + year-param = [ "year" / "YEAR" ] "=" year + + tax-id-param = [ "id" / "ID" ] "=" tax-id-enc + + salt-param = [ "salt" / "SALT" ] "=" salt + + total-param = [ "total" / "TOTAL" ] "=" amount + + signature-param = [ "sig" / "SIG" ] "=" algo ":" signature + ; Path parameters year = DIGIT DIGIT DIGIT DIGIT @@ -197,7 +222,7 @@ ; Salt remains an opaque string for the URI and is interpreted by ; the Donau system. (See semantics.) - salt = 1*( DIGIT ) + salt = 1*( ALPHA / DIGIT ) ; Query parameters and signature encoding amount = currency ":" unit [ "." fraction ] @@ -205,7 +230,7 @@ unit = 1*( DIGIT ) fraction = 1*( DIGIT ) algo = "ED25519" - signature = *( ALPHA / DIGIT ) + signature = 1*( ALPHA / DIGIT ) ]]> </artwork> </figure> @@ -213,156 +238,154 @@ <section anchor="semantics" title="Semantics"> <t> + Even if RFC3986 <xref target="RFC3986"/> explicitly writes that scheme names + are case-insensitive, lower and upper case variations are presented here to + emphasize this possibility. The applications encoding URI in a QR-code can + benefit from the possibility to encode the URI using only uppercase letters + which should result in a more compact encoding. + </t> + <t> The base of a Donau URI refers to the base URL of the Donau REST API. - It consists of the network location (host name or IP address) and MAY include + It consists of the network location (host name or IP address) and <bcp14>MAY</bcp14> include additional path segments (for example, <tt>https://admin.ch/taxes/donau/</tt>) - mapping to the Donau deployment behind reverse proxies. Validators MUST NOT - assume a specific domain naming scheme (such as <tt>donau.example</tt>) and - MUST accept bases with or without additional path components. + mapping to the Donau deployment behind reverse proxies. Validators <bcp14>MUST NOT</bcp14> + assume a specific domain naming convention or pattern + (such as <tt>donau.example</tt>) and + <bcp14>MUST</bcp14> accept bases with or without additional path components. </t> <t> - The year of a Donau URI referes to the year when the donations + The year of a Donau URI refers to the year when the donations have been done. </t> <t> - The taxid of a Donau URI referes to the taxid of the person that + The taxid of a Donau URI refers to the taxid of the person that did the donations and asks for their Donau donation statement to be verified. The format of the taxid is specific for each tax authority. - The taxid is conveyed in the URI as a single path segment using percent-encoding - per <xref target="RFC3986"/>. Implementations MUST decode <tt>taxid-enc</tt> + The taxid is conveyed in the URI as a percent-encoded query parameter as + per <xref target="RFC3986"/>. Implementations <bcp14>MUST</bcp14> decode <tt>taxid-enc</tt> by applying percent-decoding to obtain the exact UTF-8 bytes of the tax identifier - before any processing. In particular, the character '/' MUST be percent-encoded + before any processing. In particular, the character '/' <bcp14>MUST</bcp14> be percent-encoded as <tt>%2F</tt> if present in a tax identifier. </t> <t> - The salt of a Donau URI referes to the information used by the - Donau-wallet application to generate the Donau donation statement. This salt is - specific for each wallet, allowing a taxpayer to have many Donau - donation statements for the same year that should be treated as - cummulative by the validator application. The salt can also be - used to obfuscate the taxpayer ID in the donation protocol. + + The salt of a Donau URI refers to information used by a + wallet application to generate the Donau donation statement. + This salt is wallet-specific. As taxpayers <bcp14>MAY</bcp14> + use multiple wallets, tax authorities <bcp14>SHOULD</bcp14> + allowing a taxpayer to supply multiple Donau + donation statements for the same year. If the salts + are different, these should be treated as + cumulative by the validator application. The salt + <bcp14>SHOULD</bcp14> also used to obfuscate the taxpayer ID + in the donation protocol. </t> <t> The total follows the syntax from <xref target="RFC8905"/> and represents the total amount donated in this year by the given taxpayer with the given salt. Thus, given multiple 'donau' URIs - with the same salt, the maximum amount should be used, while - the amounts from 'donau' URIs with different salts should be + with the same salt, the maximum total amount should be used, while + the total amounts from 'donau' URIs with different salts should be added. </t> <t> - Parsing note: A Donau validator MUST parse a Donau URI by taking the last three - path segments as <tt>{year}/{taxid-enc}/{salt}</tt>, and treat all preceding - path segments (plus the authority) as the <tt>base</tt>. This ensures that bases - with additional path components are unambiguous even when tax identifiers contain - reserved characters that are percent-encoded. - </t> - <t> Finally, <tt>algo</tt> specifies the specific signature algorithm used; for now, only ED25519 (see <xref target="RFC8032" />) is supported. - The signature using the specified algorithm must be + The signature using the specified algorithm <bcp14>MUST</bcp14> be made over the information above (see <xref target="signature"/>) - and MUST be encoded using the Base 32 U Crockford encoding + and <bcp14>MUST</bcp14> be encoded using the Base 32 U Crockford encoding scheme <xref target="base32-U-crockford"/>. </t> <t> The default operation of applications that invoke a URI with the - Donau scheme MUST be to launch a Donau validator (if + Donau scheme <bcp14>MUST</bcp14> be to launch a Donau validator (if available). If no Donau validator is available, an application - SHOULD show a QR code with the content of the URI. If multiple - Donau validators are registered, the user SHOULD be able to choose + <bcp14>SHOULD</bcp14> show a QR code with the content of the URI. + If multiple + Donau validators are registered, the user <bcp14>SHOULD</bcp14> be able to choose which application to launch. This allows users with multiple validators to choose which validator to perform the operation with. </t> - <t> - An application SHOULD allow dereferencing a "donau://" URI even + <!--<t> + An application <bcp14>SHOULD</bcp14> allow dereferencing a "donau://" URI even if the action of that URI is not registered in the "Donau URI Actions" sub-registry. - </t> + </t>--> <t> - Donau-validators seeing a "<tt>donau://</tt>" URI MUST use HTTP over TLS when talking - to the respective network service. - Donau-validators seeing a "<tt>donau+http://</tt>" URI MUST use HTTP without TLS when talking - to the respective network service. Donau-validators SHOULD support - "<tt>donau+http://</tt>"-URIs only when run in developer or debug mode. - Validators would contact the base to obtain the public key - used for the signature. The base origin SHOULD also be shown to the - user to indicate which authority issued the proof of donation. - Alternatively, specific validation apps MAY only accept 'donau' - URLs from a specific set of hard-coded authorities and simply display - an error message when given 'donau' URLs from other authorities. - </t> + Validators <bcp14>MUST</bcp14> use HTTP over TLS when processing a "<tt>donau</tt>" URI. + Validators <bcp14>MUST</bcp14> use HTTP without TLS when processing a "<tt>donau+http</tt>" URI. + The base origin <bcp14>SHOULD</bcp14> be shown to the + user to indicate which authority issued the proof of donation. + Alternatively, specific validation apps <bcp14>MAY</bcp14> only accept 'donau' + URLs from a specific set of hard-coded authorities and simply display + an error message when given 'donau' URLs from other authorities. + </t> </section> - <section anchor="examples" title="Examples"> - <figure> - <artwork><![CDATA[ +<section anchor="examples" title="Examples"> + <figure> + <artwork><![CDATA[ ; Minimal example with a simple base and simple taxid - donau://example.com/2025/7560001010000/1234?total=EUR:15&sig=ED25519:H9PM3BW3P8MEKB34GZ0G1F7JSNVX7B8AHXRFFMS37QZM7TXZ5MWPXTEDZZGN1QRB1AFPKNCFXJB39NJHP3BAFGCZSCXHEYPHA1YJY28 + donau://example.com/?year=2025&id=7560001010000&salt=1234&total=EUR:15&sig=ED25519:H9PM3BW3P8MEKB34GZ0G1F7JSNVX7B8AHXRFFMS37QZM7TXZ5MWPXTEDZZGN1QRB1AFPKNCFXJB39NJHP3BAFGCZSCXHEYPHA1YJY28 ; Example with percent-encoded taxid containing '/' - donau://donau.test.taler.net/2025/123%2F456%2F789/1234?total=TESTKUDOS:1&sig=ED25519:B14WGS43FFPEB8JMSR6W1H8M6KH9AV33JFH376R6PM2MNH4GR24FP1C93C4ZPDG21W5WY4SASZQ4CRS427F4WJZJFZMQ5Y4HZNXGY30 + donau://donau.test.taler.net/?year=2025&id=123%2F456%2F789&salt=1234&total=TESTKUDOS:1&sig=ED25519:B14WGS43FFPEB8JMSR6W1H8M6KH9AV33JFH376R6PM2MNH4GR24FP1C93C4ZPDG21W5WY4SASZQ4CRS427F4WJZJFZMQ5Y4HZNXGY30 ; Example with a base URL that includes path components - donau://admin.ch/taxes/donau/2025/7560001010000/1234?total=EUR:15&sig=ED25519:H9PM3BW3P8MEKB34GZ0G1F7JSNVX7B8AHXRFFMS37QZM7TXZ5MWPXTEDZZGN1QRB1AFPKNCFXJB39NJHP3BAFGCZSCXHEYPHA1YJY28 + donau://admin.ch/taxes/donau/?year=2025&id=7560001010000&salt=1234&total=EUR:15&sig=ED25519:H9PM3BW3P8MEKB34GZ0G1F7JSNVX7B8AHXRFFMS37QZM7TXZ5MWPXTEDZZGN1QRB1AFPKNCFXJB39NJHP3BAFGCZSCXHEYPHA1YJY28 ]]> - </artwork> -</figure> - + </artwork> + </figure> </section> <section anchor="verification" title="Verification of a Donau URI"> <t> - The verification requires the Donau verification application to test - if a given taxpayer has got the right to be granted a tax - reduction. For doing this, the Donau verification application must - verify that the Donau-URI corresponds to a valid Donau donation - statement. The Donau verification application MUST verify the - validity of the donation statement. There are two possibilities: - signature and total are available, or at least one is not available. + The verification requires the Donau verification application to test + if a given taxpayer is entitled to a tax reduction. + For doing this, the Donau verification application must + verify that the Donau URI corresponds to a valid Donau donation + statement. The Donau verification application <bcp14>MUST</bcp14> verify the + validity of the donation statement. There are two possibilities: + signature and total are available, or at least one is not available. </t> <t> - If signature and total are available, then the verification - application will verify - that the signature is valid for the server key (see <xref - target="get-server-keys"/> to get the key). + If signature and total are available, then the verification + application <bcp14>MUST</bcp14> verify + that the signature is valid for the server key (see <xref + target="get-server-keys"/> to get the key). </t> <t> - If both are missing, the application MUST download them from - the get donation statement endpoint <xref target="get-donation-statement"/>. + If either or both are missing, the application <bcp14>MUST</bcp14> download them from + the get donation statement endpoint <xref target="get-donation-statement"/>. </t> - + </section> -<section anchor="get-server-keys" title="Access the Donau server public - keys"> +<section anchor="get-server-keys" title="Obtaining Donau Server Public Keys"> <t> - The verification app MUST have a signing public key - corresponding to the base for the given year. The key MAY be retrieved from a + The verification app <bcp14>MUST</bcp14> obtain the signing public key + corresponding to the base for the given year. + The key <bcp14>MAY</bcp14> be retrieved from a cache. If no key for this base and this year is available in the - cache, the verification app MUST download the key from the - base. The Donau server MUST provide the key at the /keys - entrypoint. If the key is not available, no verification can take place. - - The verification app SHOULD cache downloaded signing - public keys for the current year. + cache, the verification app <bcp14>MUST</bcp14> download the key from the + base. The Donau server <bcp14>MUST</bcp14> provide the key at the /keys + endpoint. If the key is not available, no verification can take place + and the validator <bcp14>MUST</bcp14> return an appropriate error. + + The verification app <bcp14>SHOULD</bcp14> cache downloaded signing + public keys for the current year. </t> <t> - + <list style="symbols"> <t>Endpoint: /keys</t> <t>Method: GET</t> <t>Syntax: base/keys</t> <t>Syntax response: defined hereunder</t> - <t>Contact: N/A</t> <t>References: [this.I-D]</t> </list> - - - - Each of the "<tt>signkeys</tt>" is valid between "<tt>stamp_start</tt>" and "<tt>stamp_expire</tt>" and the public "<tt>key</tt>" returned is encoded using Base 32 U Crockford encoding <xref target="base32-U-crockford"/>. @@ -376,9 +399,9 @@ ALPHA32 = DIGIT / LETTER DIGIT = %x30-39 ; 0-9 LETTER = %x41-48 / %x4A-4E / %x50-5A / %x61-68 / %x6A-6E / %x70-7A JSONUCrockfordString = DQUOTE UCrockford DQUOTE -EscapedChar = %x22 / %x5C / %x2F / %x62 / %x66 / %x6E / %x72 / %x74 / +EscapedChar = %x22 / %x5C / %x2F / %x62 / %x66 / %x6E / %x72 / %x74 / "u" 4HEXDIG -JSONNumber = [ "-" ] 1DIGIT *( DIGIT ) [ "." 1DIGIT *( DIGIT ) ] +JSONNumber = [ "-" ] 1DIGIT *( DIGIT ) [ "." 1DIGIT *( DIGIT ) ] [ ( "e" / "E" ) [ "+" / "-" ] 1DIGIT *( DIGIT ) ] JSONBool = "true" / "false" JSONNull = "null" @@ -388,8 +411,8 @@ JSONMember = JSONString ":" JSONException JSONException = JSONString / JSONNumber / JSONObject / JSONArray / JSONBool / JSONNull ; Specific DonauKeysResponse structure -DonauKeysResponse = "{" - JSONMemberSep +DonauKeysResponse = "{" + JSONMemberSep "}" JSONMemberSep = version , domain , base_url , currency , currency_fraction_digits , donation_units , signkeys @@ -412,61 +435,64 @@ donation_units_array = DQUOTE "donation_units" DQUOTE ":" "[" DUNK_UNIT_KEY *( ; donation unit entries differ depending on cipher DUNK_UNIT_KEY = "{" base_fields "," key_specific "}" base_fields = DQUOTE "year" DQUOTE ":" JSONNumber [ "," DQUOTE "lost" DQUOTE ":" JSONBool ] -key_specific = ( DQUOTE "rsa_pub" DQUOTE ":" JSONObject ) / +key_specific = ( DQUOTE "rsa_pub" DQUOTE ":" JSONObject ) / ( DQUOTE "cs_pub" DQUOTE ":" JSONString ) SignKey = "{" DQUOTE "key" DQUOTE ":" JSONObject "," DQUOTE "year" DQUOTE ":" JSONNumber "}" ]]> </sourcecode> -Example, a response to a GET request to the <tt>/key/</tt> endpoint. +Example, a response to a GET request to the <tt>/keys</tt> endpoint. <sourcecode> <![CDATA[ - {"signkeys": - [ "stamp_start":{"ts_s":42}, - "stamp_expire":{"ts_s":43}, - "key":"XXXXXXXXXXXXXXXX" + { "signkeys": + [ + { + "stamp_start": {"ts_s": 42 }, + "stamp_expire": {"ts_s": 43 }, + "key": "XXXXXXXXXXXXXXXX" + } ] } ]]> </sourcecode> - + </t> </section> -<section anchor="get-donation-statement" title="Get donation statement - and signature"> +<section anchor="get-donation-statement" + title="Donation Statement Retrieval"> <t> - If the Donau-URI does not contain the total or the signature, the - verification app MUST download them from the <tt>/donation-statement/</tt> + If the Donau URI does not contain the total or the signature, the + verification app <bcp14>MUST</bcp14> download them from the <tt>/donation-statement</tt> endpoint of the base.<br/> - The verification app will compute the donor hash H using SHA-512 <xref target="RFC6234"/> + The verification app <bcp14>MUST</bcp14> compute the hash of the donor + taxpayer ID <tt>hash-donor-id</tt> using SHA-512 <xref target="RFC6234"/> over the exact UTF-8 bytes of the taxpayer ID string, followed by a single NUL byte (0x00), followed by the salt string, followed by a final NUL byte (0x00): - <tt>H = SHA-512(taxid || 0x00 || salt || 0x00)</tt>. Here, <tt>taxid</tt> is the - UTF-8 string obtained by percent-decoding the <tt>taxid-enc</tt> path segment. - This produces the <tt>hash-donor-id</tt>. The verification app will contact the - base in the endpoint <tt>/donation-statement</tt> with the year and the hash-donor-id. + <tt>hash-donor-id = SHA-512(taxid || 0x00 || salt || 0x00)</tt>. + Here, <tt>taxid</tt> is the UTF-8 string obtained by percent-decoding the <tt>taxid-enc</tt> path segment. + The verification app <bcp14>MUST</bcp14> contact the + base at the endpoint <tt>/donation-statement</tt> with the year and <tt>hash-donor-id</tt>. - The <tt>hash-donor-id</tt> must be encoded using Base 32 U Crockford + The hash of the donor taxpayer ID <tt>hash-donor-id</tt> <bcp14>MUST</bcp14> be encoded + using Base 32 U Crockford encoding <xref target="base32-U-crockford"/>. - <list style="symbols"> <t>Endpoint: /donation-statement</t> <t>Method: GET</t> -<t>Syntax: base/donation-statement/{year}/{hash-donor-id}</t> -<t>Contact: N/A</t> -<t>References: [this.I-D]</t> -</list> - + <t>Syntax: base/donation-statement/{year}/{hash-donor-id}</t> + <t>References: [this.I-D]</t> + </list> -Servers implementing the donation-statement endpoint MUST respect the -following syntax; all three fields (<tt>total-field</tt>, <tt>sig-field</tt>, <tt>pub-field</tt>) MUST be included. +Servers implementing the donation-statement endpoint +<bcp14>MUST</bcp14> respect the +following syntax; all three fields (<tt>total-field</tt>, <tt>sig-field</tt>, <tt>pub-field</tt>) <bcp14>MUST</bcp14> be included. -The amount is a string formed first of the currency (in capital +The total amount is a string formed first of the currency (in capital letters) then ":" and then the value (can be an integer or a decimal number). @@ -498,15 +524,15 @@ ALPHA = %x41-5A / %x61-7A ]]> </sourcecode> - + Example of an element of USD 100.00 : <sourcecode> <![CDATA[ { - total: "USD:100", - donation_statement_sig: "SIGNATURE", - donau_pub: "EDDSA_PUBLIC_KEY" + "total": "USD:100", + "donation_statement_sig": "SIGNATURE", + "donau_pub": "EDDSA_PUBLIC_KEY" } ]]> </sourcecode> @@ -514,56 +540,54 @@ Example of an element of USD 100.00 : </t> </section> -<section anchor="signature-total-available" title="Signature and - total are available"> + + +<section anchor="signature-total-available" + title="Verification if Signature and Total are Available"> <t> - The verification app MUST verify that the signature corresponds to + The verification app <bcp14>MUST</bcp14> verify that the signature corresponds to the claimed values. - If the information is not in the URI, the verification app MUST download the total and the signature from the - base using the GET /donation-statement/ endpoint <xref - target="get-donation-statement"/>. Otherwise, it SHOULD use the - value given in the URI. + If the information is not in the URI, the verification app <bcp14>MUST</bcp14> + download the total and the signature from the + base using the GET <tt>/donation-statement</tt> endpoint <xref + target="get-donation-statement"/>. Otherwise, it <bcp14>SHOULD</bcp14> use the + value given in the URI. The verification of the signature is done using EdDSA as specified in <xref target="RFC8032" />. - The verification MAY be done with the following instructions. The signed data is the concatenation of the following fields in network byte order (big-endian): + The verification <bcp14>MAY</bcp14> be done with the following instructions. + The signed data is the concatenation of the following fields + in network byte order (big-endian): <ul> <li>size (4 bytes): 32-bit unsigned integer with the total length of the signed data in bytes.</li> <li>purpose (4 bytes): 32-bit unsigned integer with the constant value <tt>1500</tt>.</li> <li>total value (8 bytes): integer part as an unsigned 64-bit integer.</li> <li>total fraction (4 bytes): fractional part as an unsigned 32-bit integer in units of 1/100000000.</li> - <li>currency (12 bytes): ASCII, left-aligned and zero-padded to 12 bytes.</li> - <li>donor hash H (64 bytes): <tt>H = SHA-512( UTF-8(taxid) || 0x00 || UTF-8(salt) || 0x00 )</tt>.</li> + <li>currency (12 bytes): ASCII string, left-aligned with zero-padding on the right to 12 bytes.</li> + <li>hash of donor taxpayer ID (64 bytes): <tt>hash-donor-id = SHA-512( UTF-8(taxid) || 0x00 || UTF-8(salt) || 0x00 )</tt>.</li> <li>year (4 bytes): 32-bit unsigned integer (the donation year).</li> </ul> - -</t> + </t> </section> -<section anchor="signature" title="Signature of the donation statement "> + +<section anchor="signature" + title="Creating Donation Statement Signatures"> <t> The server signing the donation statement <bcp14>MUST</bcp14> use the Sign(d,message) procedure implemented as defined in <xref target="RFC8032" />. </t> - <figure anchor="figure_signature_data" title="The binary representation of the data to sign"> - <artwork name="" type="" align="left" alt=""><![CDATA[ -0 -]]></artwork> - </figure> - - - - <t> - The signature over the public key covers a 32-bit pseudo header - conceptually prefixed to the EXPIRATION and BDATA fields. - The wire format is illustrated - in <xref target="figure_rrsigwithpseudo"/>. - </t> - <figure anchor="figure_rrsigwithpseudo"> - <name>The Wire Format Used for Creating the Signature of the RRBLOCK</name> - <artwork name="" type="" alt=""> + <t> + The signature over the public key covers a 32-bit pseudo header + conceptually prefixed to the donation data fields. + The wire format is illustrated + in <xref target="figure_donausigwithpseudo"/>. + </t> + <figure anchor="figure_donausigwithpseudo"> + <name>The Format for Creating Donation Statement Signatures</name> + <artwork name="" type="" alt=""> 0 8 16 24 32 40 48 56 +-----+-----+-----+-----+-----+-----+-----+-----+ | SIZE | PURPOSE (1500) | @@ -580,71 +604,81 @@ Example of an element of USD 100.00 : +-----+-----+-----+-----+-----+-----+-----+-----+ | YEAR | +-----+-----+-----+-----+ - </artwork> - </figure> - <dl newline="false"> - <dt>SIZE:</dt> - <dd> - A 32-bit value containing the length of the signed data in bytes - in network byte order. - </dd> - <dt>PURPOSE:</dt> - <dd> - A 32-bit signature purpose flag in network byte order. The value of this - field <bcp14>MUST</bcp14> be 1500. It defines the context in which - the signature is created so that it cannot be reused in other parts - of the protocol that might include possible future extensions. - The value of this field corresponds to an entry in the - GANA "GNUnet Signature Purposes" registry <xref target="GANA"/>. - </dd> - <dt>TOTAL value:</dt> - <dd> - The integer part of the total value. Unsigned integer containing the integer part of the value for the total. It is represented on 64 bits value (in big endian), - </dd> - <dt>TOTAL fraction:</dt> - <dd> - The fractional part of the total value is represented by an unsigned integer on 32 bits (also in big endian notation). It represents the fractional part of the value in 1/100000000th of the base unit. - </dd> - <dt>TOTAL currency</dt> - <dd> - A string representing the currency. ASCII, left-aligned and zero-padded to exactly 12 bytes. - </dd> - <dt>HASH:</dt> - <dd>The SHA512 hash code for the donor ID.</dd> - <dt>YEAR:</dt> - <dd>The year on a 32 bit unsigned integer in big endian.</dd> - </dl> - </section> - -<section anchor="signature-verification" title="Signature verification for a donation statement"> + </artwork> + </figure> + <dl newline="false"> + <dt>SIZE:</dt> + <dd> + A 32-bit value containing the length of the signed data in bytes + in network byte order. + </dd> + <dt>PURPOSE:</dt> + <dd> + A 32-bit signature purpose flag in network byte order. The value of this + field <bcp14>MUST</bcp14> be 1500. It defines the context in which + the signature is created so that it cannot be reused in other parts + of the protocol that might include possible future extensions. + The value of this field corresponds to an entry in the + GANA "GNUnet Signature Purposes" registry <xref target="GANA"/>. + </dd> + <dt>TOTAL value:</dt> + <dd> + The integer part of the total value. + Unsigned integer containing the integer part of the value for the total. + It is represented using a 64 bit value (in big endian). + </dd> + <dt>TOTAL fraction:</dt> + <dd> + The fractional part of the total value is represented by an + unsigned integer on 32 bits (also in big endian notation). + It represents the fractional part of the value in 1/100000000th of the base unit. + </dd> + <dt>TOTAL currency</dt> + <dd> + A string representing the currency. ASCII, left-aligned and zero-padded to exactly 12 bytes. + </dd> + <dt>HASH:</dt> + <dd>The SHA512 hash code for the donor ID.</dd> + <dt>YEAR:</dt> + <dd>The year on a 32 bit unsigned integer in big endian.</dd> + </dl> +</section> + +<section anchor="signature-verification" + title="Validating Donation Statement Signatures"> <t> -The signature verification step is taking the data presented in the figure <xref target="figure_signature_data" /> as -input. Signature MUST be verified using the EdDSA scheme described in -<xref target="RFC8032" /> the procedure is Verify(zk,message,signature). Public key and signature are given -encoded in Base 32 U Crockford MUST first be decoded to get a binary -out of it. + The signature verification step is taking the data presented in the + figure <xref target="figure_donausigwithpseudo" /> as input. + The signature <bcp14>MUST</bcp14> be verified using the EdDSA scheme described in + <xref target="RFC8032" /> the procedure is + <tt>Verify(zk,message,signature)</tt>. + Public key and signature, which are + encoded in Base 32 U Crockford in the URL, + <bcp14>MUST</bcp14> first be decoded to obtain the + respective binary value. </t> <t> - The Sign(d,message) and Verify(zk,message,signature) procedures <bcp14>MUST</bcp14> - be implemented as defined in <xref target="RFC8032" />. - </t> - + The Sign(d,message) and Verify(zk,message,signature) procedures <bcp14>MUST</bcp14> + be implemented as defined in <xref target="RFC8032" />. + </t> </section> -<section anchor="base32-U-crockford" title="Base 32 representation of - binary data"> -<t>All binary data MUST be encoded to be transmitted. For encoding, one -MUST use the Base32 U Crockford encoding. This is a variation of the -base32 encoding <xref target ="RFC4648" />. This encoding is presented -in details in the appendix of the RFC for GNU Name System <xref target="RFC9498" /> -</t> -<t> -The encoding works similarly to the standard, but uses another Base 32 -Alphabet. The new alphabet is given in the Table <xref target="figure_base32_encoding" />, below. -</t> -<figure anchor="figure_base32_encoding" title="The Base 32 Encoding Alphabet."> - <artwork name="" type="" align="left" alt="table where value beween 0 and 9 are encoded with the character corresponding to the number. Then between 10 and 31, we have all the letters expect I, L, O, U that could be missleading (OCR may not recognize them properly). Pading is the char ="><![CDATA[ +<section anchor="base32-U-crockford" + title="Base 32 Representation of Binary Data"> + <t> + All binary data <bcp14>MUST</bcp14> be encoded to be transmitted. For encoding, one + <bcp14>MUST</bcp14> use the Base32 U Crockford encoding. This is a variation of the + base32 encoding <xref target ="RFC4648" />. This encoding is presented + in detail in the appendix of the RFC for GNU Name System <xref target="RFC9498" /> + </t> + <t> + The encoding works similarly to the standard, but uses another Base 32 + Alphabet. The new alphabet is given in the Table <xref target="figure_base32_encoding" />, below. + </t> + + <figure anchor="figure_base32_encoding" title="The Base 32 Encoding Alphabet."> + <artwork name="" type="" align="left" alt="table where value between 0 and 9 are encoded with the character corresponding to the number. Then between 10 and 31, we have all the letters expect I, L, O, U that could be misleading (OCR may not recognize them properly). Padding is the char ="><![CDATA[ Value Encoding Value Encoding Value Encoding Value Encoding 0 0 9 9 18 J 27 V 1 1 10 A 19 K 28 W @@ -657,14 +691,15 @@ Value Encoding Value Encoding Value Encoding Value Encoding 8 8 17 H 26 T ]]> - </artwork> -</figure> - -<t> -To prevent optical character reading (OCR) problems, a system decoding binary data encoded with base 32 U Crockford MUST -accept the codes presented in the Table <xref target="figure_base32_decoding"/>, below. System reading a U -MUST evaluate it as a V. -</t> + </artwork> + </figure> + + <t> + To prevent optical character reading (OCR) problems, a system decoding + binary data encoded with base 32 U Crockford <bcp14>MUST</bcp14> + accept the codes presented in the Table <xref target="figure_base32_decoding"/>, below. + System reading a <tt>U</tt> <bcp14>MUST</bcp14> evaluate it as a <tt>V</tt>. + </t> <figure anchor="figure_base32_decoding" title="The Base 32 Decoding Alphabet."> <artwork name="" type="" align="left" alt=""><![CDATA[ @@ -679,22 +714,84 @@ Value Encoding Value Encoding Value Encoding Value Encoding 7 7 16 G|g 25 S|s 8 8 17 H|h 26 T|t ]]></artwork> - </figure> - + </figure> + + +</section> + +<section anchor="security" title="Security Considerations"> + <t> + Donau validators <bcp14>SHOULD</bcp14> support + "<tt>donau+http://</tt>"-URIs only when run in developer or debug mode + as otherwise the integrity and authenticity of the public key + cannot be assured. + </t> + <t> + Running "<tt>donau+http://</tt>"-URIs on a production server + <bcp14>MUST NOT</bcp14> be permitted, since it would be a security issue. + This scheme is intended only for testing purposes, + for instance on <tt>localhost</tt>. + </t> + <t> + Validator applications <bcp>MUST</bcp> include protections + against repeated validations of the same donation statement + with the same salt and year. Specifically, when summing up + multiple donation statements for the same taxpayer and + tax year, the <bcp>MUST</bcp> keep enough state to add + up the maximum total amounts per salt if multiple donation + statements are submitted with the same salt. + </t> +</section> + + +<section anchor="iana" title="IANA Considerations"> + <name slugifiedName="name-iana-considerations">IANA Considerations</name> + <t> + IANA maintains the "Uniform Resource Identifier (URI) Schemes" + registry that contains an entry for the 'donau' URI scheme. IANA is + requested to update that entry to reference this document when + published as an RFC. + </t> + <dl indent="3" newline="false" spacing="normal" pn="section-9-2"> + <dt>Scheme name:</dt> + <dd> donau</dd> + <dt>Status:</dt> + <dd> provisional</dd> + <dt>URI scheme syntax:</dt> + <dd>See <xref target="syntax" format="default" sectionFormat="of" derivedContent="Section 3"/> of [This.I-D].</dd> + <dt>URI scheme semantics:</dt> + <dd>See <xref target="semantics" format="default" sectionFormat="of" derivedContent="Section 4"/> of [This.I-D].</dd> + <dt>Applications/protocols that use this scheme name:</dt> + <dd> GNU Taler</dd> + <dt>Contact:</dt> + <dd> + <t><contact fullname="Christian Grothoff"/> &lt;grothoff@gnu.org&gt;</t> + </dd> + <dt>Change controller:</dt> + <dd> + <t><contact fullname="Christian Grothoff"/> &lt;grothoff@gnu.org&gt;</t> + </dd> + <dt>References:</dt> + <dd> See <xref target="refs" format="default" sectionFormat="of" derivedContent="Section 13"/> of [This.I-D].</dd> + </dl> +</section> - </section> +</middle> - <section anchor="appendix-test-vectors" title="Appendix. Test Vector: Verify from URI"> - <t> - This appendix shows how to verify a donation statement starting from a - received URI. Public key is fetched from the Donau base. - </t> +<back> + + +<section anchor="appendix-test-vectors" title="Appendix. Test Vector: Verify from URI"> + <t> + This appendix shows how to verify a donation statement starting from a + received URI. Public key is fetched from the Donau base. + </t> - <figure> - <artwork><![CDATA[ + <figure> + <artwork><![CDATA[ Example URI: -donau://donau.test.taler.net/2025/123%2F456%2F789/AWNFDRFT0WX45W4Y32A9DJA03S1EF66GFQZ9EV5EF9JTHWZ37WR0?total=TESTKUDOS:1&sig=ED25519:B14WGS43FFPEB8JMSR6W1H8M6KH9AV33JFH376R6PM2MNH4GR24FP1C93C4ZPDG21W5WY4SASZQ4CRS427F4WJZJFZMQ5Y4HZNXGY30 +donau://donau.test.taler.net/?year=2025&id=123%2F456%2F789&salt=AWNFDRFT0WX45W4Y32A9DJA03S1EF66GFQZ9EV5EF9JTHWZ37WR0&total=TESTKUDOS:1&sig=ED25519:B14WGS43FFPEB8JMSR6W1H8M6KH9AV33JFH376R6PM2MNH4GR24FP1C93C4ZPDG21W5WY4SASZQ4CRS427F4WJZJFZMQ5Y4HZNXGY30 Extracted fields: - base: donau.test.taler.net @@ -707,13 +804,13 @@ Extracted fields: Fetched public key for year 2025 from https://donau.test.taler.net/keys: - pub: 2FRN2CAK9DMDWE157W6HY97RAVSP0ZCCC08X9N6JD2MK7413XXZG - ]]></artwork> - </figure> +]]></artwork> + </figure> - <t>Verification steps:</t> - <list style="numbers"> + <t>Verification steps:</t> + <list style="numbers"> <t>Input (URI):<br/> -<tt>donau://donau.test.taler.net/2025/123%2F456%2F789/AWNFDRFT0WX45W4Y32A9DJA03S1EF66GFQZ9EV5EF9JTHWZ37WR0?total=TESTKUDOS:1&amp;sig=ED25519:B14WGS43FFPEB8JMSR6W1H8M6KH9AV33JFH376R6PM2MNH4GR24FP1C93C4ZPDG21W5WY4SASZQ4CRS427F4WJZJFZMQ5Y4HZNXGY30</tt></t> +<tt>donau://donau.test.taler.net/?year=2025&amp;id=123%2F456%2F789&amp;salt=AWNFDRFT0WX45W4Y32A9DJA03S1EF66GFQZ9EV5EF9JTHWZ37WR0&amp;total=TESTKUDOS:1&amp;sig=ED25519:B14WGS43FFPEB8JMSR6W1H8M6KH9AV33JFH376R6PM2MNH4GR24FP1C93C4ZPDG21W5WY4SASZQ4CRS427F4WJZJFZMQ5Y4HZNXGY30</tt></t> <t>Parse fields:<br/> - base: <tt>donau.test.taler.net</tt><br/> - year: <tt>2025</tt> (4 digits)<br/> @@ -724,13 +821,13 @@ Fetched public key for year 2025 from https://donau.test.taler.net/keys: - sig (Crockford Base32, algorithm ED25519): <tt>B14WGS...XGY30</tt></t> <t>Public signing key (Crockford Base32) (from <tt>/keys</tt>):<br/> <tt>2FRN2CAK9DMDWE157W6HY97RAVSP0ZCCC08X9N6JD2MK7413XXZG</tt></t> - <t>Donor hash <tt>H</tt> = <tt>SHA-512( UTF-8(taxid) || 0x00 || UTF-8(salt) || 0x00 )</tt>:<br/> + <t>Hash of the donor taxpayer ID <tt>hash-donor-id</tt> = <tt>SHA-512( UTF-8(taxid) || 0x00 || UTF-8(salt) || 0x00 )</tt>:<br/> - length: 64 bytes<br/> - hex:<br/> <tt>4aaa1e16fc5be44842b863b1f17da39296ca7b3529a720e11aba9c8bd729f7a1e2bb0b9a39c02d271da5dd15aea66ce95be78bcaf380de19a0bdbcd8a7938f1b</tt><br/> - Crockford Base32 (for HTTP endpoints):<br/> <tt>9AN1W5QWBFJ4GGNRCERZ2ZD3JABCMYSN56KJ1R8TQAE8QNS9YYGY5ERBK8WW0B973PJXT5DEMSPEJPZ7HF5F706Y36GBVF6RMY9RY6R</tt></t> - <t>Amount encoding (<tt>TALER_AmountNBO</tt>):<br/> + <t>Total amount encoding (<tt>TALER_AmountNBO</tt>):<br/> - currency (12 bytes): <tt>"TESTKUDOS"</tt> then <tt>0x00</tt> x 3<br/> - value (uint64 BE): <tt>1</tt> -> <tt>0x0000000000000001</tt><br/> - fraction (uint32 BE): <tt>0</tt> -> <tt>0x00000000</tt></t> @@ -740,7 +837,7 @@ Fetched public key for year 2025 from https://donau.test.taler.net/keys: - [0008..0015] 8 bytes <tt>amount.value</tt>: <tt>0x0000000000000001</tt><br/> - [0016..0019] 4 bytes <tt>amount.fraction</tt>: <tt>0x00000000</tt><br/> - [0020..0031] 12 bytes <tt>amount.currency</tt>: <tt>54 45 53 54 4b 55 44 4f 53 00 00 00</tt> ("TESTKUDOS\x00\x00\x00")<br/> - - [0032..0095] 64 bytes <tt>i.hash</tt>: donor hash <tt>H</tt><br/> + - [0032..0095] 64 bytes <tt>i.hash</tt>: hash of donor taxpayer ID <tt>hash-donor-id</tt><br/> - [0096..0099] 4 bytes <tt>year</tt>: <tt>0x000007E9</tt> (2025)</t> <t>Message <tt>M</tt> (hex, 100 bytes):<br/> <tt>00000064 000005dc 0000000000000001 00000000 544553544b55444f53000000 4aaa1e16fc5be44842b863b1f17da39296ca7b3529a720e11aba9c8bd729f7a1e2bb0b9a39c02d271da5dd15aea66ce95be78bcaf380de19a0bdbcd8a7938f1b 000007e9</tt></t> @@ -754,20 +851,14 @@ Fetched public key for year 2025 from https://donau.test.taler.net/keys: - length: 32 bytes<br/> - hex:<br/> <tt>13f15131534b68de38253f0d1f24f856f3607d8c6011d4d4d268a9339023ef7f</tt></t> - <t>Verification (expected): call <tt>crypto_sign_verify_detached(sig, M, 100, pubkey)</tt>. The result MUST indicate a valid signature for this vector.</t> - <t>Negative check (optional): flip one bit of <tt>M</tt> or <tt>sig</tt> and repeat; verification MUST fail.</t> + <t>Verification (expected): call <tt>crypto_sign_verify_detached(sig, M, 100, pubkey)</tt>. The result <bcp14>MUST</bcp14> indicate a valid signature for this vector.</t> + <t>Negative check (optional): flip one bit of <tt>M</tt> or <tt>sig</tt> and repeat; verification <bcp14>MUST</bcp14> fail.</t> </list> - </section> - - - - +</section> -</middle> -<back> - <references title="Normative References"> + <references anchor="refs" title="Normative References"> &RFC2119; @@ -777,35 +868,47 @@ Fetched public key for year 2025 from https://donau.test.taler.net/keys: &RFC5234; - &RFC6234; + &RFC6234; - &RFC8032; + &RFC8032; - &RFC9498; + &RFC9498; - &RFC8905; + &RFC8905; </references> <references title="Informational References"> - &RFC4648; - - - <reference anchor="GANA" target="https://gana.gnunet.org/"> - <front> - <title>GNUnet Assigned Numbers Authority (GANA)</title> - <author><organization>GNUnet e.V.</organization> - </author> - <date month="April" year="2020" /> - </front> - </reference> - + &RFC4648; + + + <reference anchor="GANA" target="https://gana.gnunet.org/"> + <front> + <title>GNUnet Assigned Numbers Authority (GANA)</title> + <author><organization>GNUnet e.V.</organization> + </author> + <date month="April" year="2020" /> + </front> + </reference> + + <reference anchor="BaThesis" target="https://www.taler.net/papers/donau-thesis.pdf"> + <front> + <title>Tax-deductable Privacy-Preserving Donations</title> + <author initials="J.C." surname="Casaburi" fullname="Johannes Casaburi"> + <organization>Bern University of Applied Science, Bachelor Thesis</organization> + </author> + <author initials="L.M." surname="Matya" fullname="Lukas Matya"> + <organization>Bern University of Applied Science, Bachelor Thesis</organization> + </author> + </front> + </reference> </references> <!-- Change Log -v00 2022-11-11 CG Initial version +v00 2025-10-17 CG Initial version +v01 2025-10-21 EB Including first reviews (motivations + change in URI structure) --> </back> </rfc> diff --git a/draft-grothoff-donau-01.xml b/draft-grothoff-donau-01.xml @@ -56,7 +56,7 @@ </address> </author> - + <author fullname="Bohdan Potuzhnyi" initials="B.P." surname="Potuzhnyi"> <organization>Bern University of Applied Sciences</organization> <address> @@ -71,7 +71,7 @@ </address> </author> - + <author fullname="Florian Dold" initials="F.D." surname="Dold"> <organization>Taler Systems AG</organization> <address> @@ -86,7 +86,7 @@ </address> </author> - + <date day="21" month="October" year="2025" /> <!-- Meta-data Declarations --> @@ -111,7 +111,7 @@ sum of donations a taxpayer made to recognized charities over a year. Donors would submit 'donau' URLs (or QR codes with 'donau' URLs) to tax authorities to have their donations - recognized by the tax authority as tax-deductable + recognized by the tax authority as tax-deductible expenditures. The application logic to verify the validity of the donation is triggered by 'donau' URIs. The validator application would then typically confirm to the tax official @@ -119,7 +119,7 @@ total amount donated as well as the taxpayer identification number and the year of the donation. Multiple URIs could be submitted per donor, and the application can correctly - determine which submissions are cummulative and which ones are + determine which submissions are cumulative and which ones are redundant. </t> @@ -134,55 +134,67 @@ compatible 'donau' URIs as the URI scheme is reasonably generic. </t> <t> - The validation tool will be registered for all donau:// URIs. Since each taxation authority will run its own server, it will not be possible to write inside the validation tool all the possible (changing) list of tax authorities servers. Hence a new URI scheme is needed that will triger the validation tool for any host, regardless of the name of the host. + The validation tool will be registered for all donau:// URIs. + Since each taxation authority will typically use a different + domain, it will not be feasible to encode all the + domains of tax authorities servers inside the validation tool. + Hence a new URI scheme is needed that will trigger the validation + tool for any domain name. </t> </abstract> </front> - <middle> +<middle> <section anchor="introduction" title="Introduction"> <t> - This document defines the 'donau' Uniform Resource Identifier (URI) <xref target="RFC3986" /> scheme - for triggering interactions with Donau validators. + This document defines the 'donau' Uniform Resource Identifier (URI) + <xref target="RFC3986" /> scheme for triggering interactions with + Donau validators. </t> <section title="Objective"> -<t> - A 'donau' URI always instructs a Donau validator to perform the - validation of a Donau donation statement. - A 'donau' URI consists of the reference to the authority - that signed the statement, an identifier for the specific taxpayer, - the year of the donation, a salt and optional parameters. - Optional parameters include the amount donated by the - taxpayer and the signature of the Donau donation statement. -</t> -<t>This specification is based on the Bachelor Thesis of Casaburi and Matya <xref target="BaThesis" /> presenting the solution and the first implementation of a Donau system. </t> + <t> + A 'donau' URI always instructs a Donau validator to perform the + validation of a Donau donation statement. + A 'donau' URI consists of the reference to the authority + that signed the statement, an identifier for the specific taxpayer, + the year of the donation, a salt and optional parameters. + Optional parameters include the total amount donated by the + taxpayer and the signature of the Donau donation statement. + </t> + <t> + This specification is based on the Bachelor Thesis of + Casaburi and Matya <xref target="BaThesis" /> presenting the + solution and the first implementation of a Donau system. + </t> </section> + + <section title="Requirements Language"> -<t> - The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", - "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and - "OPTIONAL" in this document are to be interpreted as described in BCP 14 - <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, - they appear in all capitals, as shown here. -</t> + <t> + The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and + "OPTIONAL" in this document are to be interpreted as described in BCP 14 + <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, + they appear in all capitals, as shown here. + </t> </section> </section> <section anchor="syntax" - title="Syntax of a 'donau' URI"> + title="Syntax of a 'donau' URI"> <t> This document uses the Augmented Backus-Naur Form (ABNF) of <xref target="RFC5234"/>. </t> <figure> <artwork type="abnf"><![CDATA[ ; Scheme and high-level structure - scheme = "donau://" / "DONAU://" / "donau+http://" / "DONAU+HTTP://" - donau-URI = scheme base "?" year-param "&" taxid-param "&" salt-param - "&" amount-param "&" sig-param ] + scheme = "donau" / "DONAU" / "donau+http" / "DONAU+HTTP" + donau-URI = scheme "://" base "?" year-param "&" taxid-param "&" salt-param + ("&" total-param "&" sig-param)? ; The base is the HTTP(S) origin plus optional path segments that ; identify the Donau REST API deployment. Everything before the last @@ -193,12 +205,12 @@ tax-id-param = [ "id" / "ID" ] "=" tax-id-enc - salt-param = [ "salt" / "SALT" ] "=" alt - - amount-param = [ "total" / "TOTAL" ] "=" amount + salt-param = [ "salt" / "SALT" ] "=" salt + + total-param = [ "total" / "TOTAL" ] "=" amount signature-param = [ "sig" / "SIG" ] "=" algo ":" signature - + ; Path parameters year = DIGIT DIGIT DIGIT DIGIT @@ -210,7 +222,7 @@ ; Salt remains an opaque string for the URI and is interpreted by ; the Donau system. (See semantics.) - salt = 1*( DIGIT ) + salt = 1*( ALPHA / DIGIT ) ; Query parameters and signature encoding amount = currency ":" unit [ "." fraction ] @@ -218,99 +230,103 @@ unit = 1*( DIGIT ) fraction = 1*( DIGIT ) algo = "ED25519" - signature = *( ALPHA / DIGIT ) + signature = 1*( ALPHA / DIGIT ) ]]> </artwork> </figure> </section> <section anchor="semantics" title="Semantics"> - <t> Even if RFC3986 <xref target="RFC3986"/> explicitely writes that scheme names are case insensitive, lower and uper case variations are presented here to emphase this possibility. The applications encoding URI in a QR-code can profite from the possibility to encode the URI in upercase only which may be more efficient. + <t> + Even if RFC3986 <xref target="RFC3986"/> explicitly writes that scheme names + are case-insensitive, lower and upper case variations are presented here to + emphasize this possibility. The applications encoding URI in a QR-code can + benefit from the possibility to encode the URI using only uppercase letters + which should result in a more compact encoding. </t> <t> The base of a Donau URI refers to the base URL of the Donau REST API. - It consists of the network location (host name or IP address) and MAY include + It consists of the network location (host name or IP address) and <bcp14>MAY</bcp14> include additional path segments (for example, <tt>https://admin.ch/taxes/donau/</tt>) - mapping to the Donau deployment behind reverse proxies. Validators MUST NOT - assume a specific domain naming scheme (such as <tt>donau.example</tt>) and - MUST accept bases with or without additional path components. + mapping to the Donau deployment behind reverse proxies. Validators <bcp14>MUST NOT</bcp14> + assume a specific domain naming convention or pattern + (such as <tt>donau.example</tt>) and + <bcp14>MUST</bcp14> accept bases with or without additional path components. </t> <t> - The year of a Donau URI referes to the year when the donations + The year of a Donau URI refers to the year when the donations have been done. </t> <t> - The taxid of a Donau URI referes to the taxid of the person that + The taxid of a Donau URI refers to the taxid of the person that did the donations and asks for their Donau donation statement to be verified. The format of the taxid is specific for each tax authority. - The taxid is conveyed in the URI as a single path segment using percent-encoding - per <xref target="RFC3986"/>. Implementations MUST decode <tt>taxid-enc</tt> + The taxid is conveyed in the URI as a percent-encoded query parameter as + per <xref target="RFC3986"/>. Implementations <bcp14>MUST</bcp14> decode <tt>taxid-enc</tt> by applying percent-decoding to obtain the exact UTF-8 bytes of the tax identifier - before any processing. In particular, the character '/' MUST be percent-encoded + before any processing. In particular, the character '/' <bcp14>MUST</bcp14> be percent-encoded as <tt>%2F</tt> if present in a tax identifier. </t> <t> - The salt of a Donau URI referes to the information used by the - Donau-wallet application to generate the Donau donation statement. This salt is - specific for each wallet, allowing a taxpayer to have many Donau - donation statements for the same year that should be treated as - cummulative by the validator application. The salt can also be - used to obfuscate the taxpayer ID in the donation protocol. + + The salt of a Donau URI refers to information used by a + wallet application to generate the Donau donation statement. + This salt is wallet-specific. As taxpayers <bcp14>MAY</bcp14> + use multiple wallets, tax authorities <bcp14>SHOULD</bcp14> + allowing a taxpayer to supply multiple Donau + donation statements for the same year. If the salts + are different, these should be treated as + cumulative by the validator application. The salt + <bcp14>SHOULD</bcp14> also used to obfuscate the taxpayer ID + in the donation protocol. </t> <t> The total follows the syntax from <xref target="RFC8905"/> and represents the total amount donated in this year by the given taxpayer with the given salt. Thus, given multiple 'donau' URIs - with the same salt, the maximum amount should be used, while - the amounts from 'donau' URIs with different salts should be + with the same salt, the maximum total amount should be used, while + the total amounts from 'donau' URIs with different salts should be added. </t> <t> Finally, <tt>algo</tt> specifies the specific signature algorithm used; for now, only ED25519 (see <xref target="RFC8032" />) is supported. - The signature using the specified algorithm must be + The signature using the specified algorithm <bcp14>MUST</bcp14> be made over the information above (see <xref target="signature"/>) - and MUST be encoded using the Base 32 U Crockford encoding + and <bcp14>MUST</bcp14> be encoded using the Base 32 U Crockford encoding scheme <xref target="base32-U-crockford"/>. </t> <t> The default operation of applications that invoke a URI with the - Donau scheme MUST be to launch a Donau validator (if + Donau scheme <bcp14>MUST</bcp14> be to launch a Donau validator (if available). If no Donau validator is available, an application - SHOULD show a QR code with the content of the URI. If multiple - Donau validators are registered, the user SHOULD be able to choose + <bcp14>SHOULD</bcp14> show a QR code with the content of the URI. + If multiple + Donau validators are registered, the user <bcp14>SHOULD</bcp14> be able to choose which application to launch. This allows users with multiple validators to choose which validator to perform the operation with. </t> <!--<t> - An application SHOULD allow dereferencing a "donau://" URI even + An application <bcp14>SHOULD</bcp14> allow dereferencing a "donau://" URI even if the action of that URI is not registered in the "Donau URI Actions" sub-registry. </t>--> <t> - Donau-validators seeing a "<tt>donau://</tt>" URI MUST use HTTP over TLS when talking - to the respective network service. - Donau-validators seeing a "<tt>donau+http://</tt>" URI MUST use HTTP without TLS when talking - to the respective network service. Donau-validators SHOULD support - "<tt>donau+http://</tt>"-URIs only when run in developer or debug mode. - Validators would contact the base to obtain the public key - used for the signature. The base origin SHOULD also be shown to the - user to indicate which authority issued the proof of donation. - Alternatively, specific validation apps MAY only accept 'donau' - URLs from a specific set of hard-coded authorities and simply display - an error message when given 'donau' URLs from other authorities. + Validators <bcp14>MUST</bcp14> use HTTP over TLS when processing a "<tt>donau</tt>" URI. + Validators <bcp14>MUST</bcp14> use HTTP without TLS when processing a "<tt>donau+http</tt>" URI. + The base origin <bcp14>SHOULD</bcp14> be shown to the + user to indicate which authority issued the proof of donation. + Alternatively, specific validation apps <bcp14>MAY</bcp14> only accept 'donau' + URLs from a specific set of hard-coded authorities and simply display + an error message when given 'donau' URLs from other authorities. </t> - <t> - Running "<tt>donau+http://</tt>"-URIs on a productive server MUST NOT be permitted, since it would be a huge security issue. These scheme is only used for testing purposes, for instance on <tt>localhost</tt>. - </t> - </section> - <section anchor="examples" title="Examples"> - <figure> - <artwork><![CDATA[ +<section anchor="examples" title="Examples"> + <figure> + <artwork><![CDATA[ ; Minimal example with a simple base and simple taxid donau://example.com/?year=2025&id=7560001010000&salt=1234&total=EUR:15&sig=ED25519:H9PM3BW3P8MEKB34GZ0G1F7JSNVX7B8AHXRFFMS37QZM7TXZ5MWPXTEDZZGN1QRB1AFPKNCFXJB39NJHP3BAFGCZSCXHEYPHA1YJY28 @@ -320,61 +336,56 @@ ; Example with a base URL that includes path components donau://admin.ch/taxes/donau/?year=2025&id=7560001010000&salt=1234&total=EUR:15&sig=ED25519:H9PM3BW3P8MEKB34GZ0G1F7JSNVX7B8AHXRFFMS37QZM7TXZ5MWPXTEDZZGN1QRB1AFPKNCFXJB39NJHP3BAFGCZSCXHEYPHA1YJY28 ]]> - </artwork> -</figure> - + </artwork> + </figure> </section> <section anchor="verification" title="Verification of a Donau URI"> <t> - The verification requires the Donau verification application to test - if a given taxpayer has got the right to be granted a tax - reduction. For doing this, the Donau verification application must - verify that the Donau-URI corresponds to a valid Donau donation - statement. The Donau verification application MUST verify the - validity of the donation statement. There are two possibilities: - signature and total are available, or at least one is not available. + The verification requires the Donau verification application to test + if a given taxpayer is entitled to a tax reduction. + For doing this, the Donau verification application must + verify that the Donau URI corresponds to a valid Donau donation + statement. The Donau verification application <bcp14>MUST</bcp14> verify the + validity of the donation statement. There are two possibilities: + signature and total are available, or at least one is not available. </t> <t> - If signature and total are available, then the verification - application will verify - that the signature is valid for the server key (see <xref - target="get-server-keys"/> to get the key). + If signature and total are available, then the verification + application <bcp14>MUST</bcp14> verify + that the signature is valid for the server key (see <xref + target="get-server-keys"/> to get the key). </t> <t> - If both are missing, the application MUST download them from - the get donation statement endpoint <xref target="get-donation-statement"/>. + If either or both are missing, the application <bcp14>MUST</bcp14> download them from + the get donation statement endpoint <xref target="get-donation-statement"/>. </t> - + </section> -<section anchor="get-server-keys" title="Access the Donau server public - keys"> +<section anchor="get-server-keys" title="Obtaining Donau Server Public Keys"> <t> - The verification app MUST have a signing public key - corresponding to the base for the given year. The key MAY be retrieved from a + The verification app <bcp14>MUST</bcp14> obtain the signing public key + corresponding to the base for the given year. + The key <bcp14>MAY</bcp14> be retrieved from a cache. If no key for this base and this year is available in the - cache, the verification app MUST download the key from the - base. The Donau server MUST provide the key at the /keys - entrypoint. If the key is not available, no verification can take place. - - The verification app SHOULD cache downloaded signing - public keys for the current year. + cache, the verification app <bcp14>MUST</bcp14> download the key from the + base. The Donau server <bcp14>MUST</bcp14> provide the key at the /keys + endpoint. If the key is not available, no verification can take place + and the validator <bcp14>MUST</bcp14> return an appropriate error. + + The verification app <bcp14>SHOULD</bcp14> cache downloaded signing + public keys for the current year. </t> <t> - + <list style="symbols"> <t>Endpoint: /keys</t> <t>Method: GET</t> <t>Syntax: base/keys</t> <t>Syntax response: defined hereunder</t> - <t>Contact: N/A</t> <t>References: [this.I-D]</t> </list> - - - - Each of the "<tt>signkeys</tt>" is valid between "<tt>stamp_start</tt>" and "<tt>stamp_expire</tt>" and the public "<tt>key</tt>" returned is encoded using Base 32 U Crockford encoding <xref target="base32-U-crockford"/>. @@ -388,9 +399,9 @@ ALPHA32 = DIGIT / LETTER DIGIT = %x30-39 ; 0-9 LETTER = %x41-48 / %x4A-4E / %x50-5A / %x61-68 / %x6A-6E / %x70-7A JSONUCrockfordString = DQUOTE UCrockford DQUOTE -EscapedChar = %x22 / %x5C / %x2F / %x62 / %x66 / %x6E / %x72 / %x74 / +EscapedChar = %x22 / %x5C / %x2F / %x62 / %x66 / %x6E / %x72 / %x74 / "u" 4HEXDIG -JSONNumber = [ "-" ] 1DIGIT *( DIGIT ) [ "." 1DIGIT *( DIGIT ) ] +JSONNumber = [ "-" ] 1DIGIT *( DIGIT ) [ "." 1DIGIT *( DIGIT ) ] [ ( "e" / "E" ) [ "+" / "-" ] 1DIGIT *( DIGIT ) ] JSONBool = "true" / "false" JSONNull = "null" @@ -400,8 +411,8 @@ JSONMember = JSONString ":" JSONException JSONException = JSONString / JSONNumber / JSONObject / JSONArray / JSONBool / JSONNull ; Specific DonauKeysResponse structure -DonauKeysResponse = "{" - JSONMemberSep +DonauKeysResponse = "{" + JSONMemberSep "}" JSONMemberSep = version , domain , base_url , currency , currency_fraction_digits , donation_units , signkeys @@ -424,61 +435,64 @@ donation_units_array = DQUOTE "donation_units" DQUOTE ":" "[" DUNK_UNIT_KEY *( ; donation unit entries differ depending on cipher DUNK_UNIT_KEY = "{" base_fields "," key_specific "}" base_fields = DQUOTE "year" DQUOTE ":" JSONNumber [ "," DQUOTE "lost" DQUOTE ":" JSONBool ] -key_specific = ( DQUOTE "rsa_pub" DQUOTE ":" JSONObject ) / +key_specific = ( DQUOTE "rsa_pub" DQUOTE ":" JSONObject ) / ( DQUOTE "cs_pub" DQUOTE ":" JSONString ) SignKey = "{" DQUOTE "key" DQUOTE ":" JSONObject "," DQUOTE "year" DQUOTE ":" JSONNumber "}" ]]> </sourcecode> -Example, a response to a GET request to the <tt>/key/</tt> endpoint. +Example, a response to a GET request to the <tt>/keys</tt> endpoint. <sourcecode> <![CDATA[ - {"signkeys": - [ "stamp_start":{"ts_s":42}, - "stamp_expire":{"ts_s":43}, - "key":"XXXXXXXXXXXXXXXX" + { "signkeys": + [ + { + "stamp_start": {"ts_s": 42 }, + "stamp_expire": {"ts_s": 43 }, + "key": "XXXXXXXXXXXXXXXX" + } ] } ]]> </sourcecode> - + </t> </section> -<section anchor="get-donation-statement" title="Get donation statement - and signature"> +<section anchor="get-donation-statement" + title="Donation Statement Retrieval"> <t> - If the Donau-URI does not contain the total or the signature, the - verification app MUST download them from the <tt>/donation-statement/</tt> + If the Donau URI does not contain the total or the signature, the + verification app <bcp14>MUST</bcp14> download them from the <tt>/donation-statement</tt> endpoint of the base.<br/> - The verification app will compute the donor hash H using SHA-512 <xref target="RFC6234"/> + The verification app <bcp14>MUST</bcp14> compute the hash of the donor + taxpayer ID <tt>hash-donor-id</tt> using SHA-512 <xref target="RFC6234"/> over the exact UTF-8 bytes of the taxpayer ID string, followed by a single NUL byte (0x00), followed by the salt string, followed by a final NUL byte (0x00): - <tt>H = SHA-512(taxid || 0x00 || salt || 0x00)</tt>. Here, <tt>taxid</tt> is the - UTF-8 string obtained by percent-decoding the <tt>taxid-enc</tt> path segment. - This produces the <tt>hash-donor-id</tt>. The verification app will contact the - base in the endpoint <tt>/donation-statement</tt> with the year and the hash-donor-id. + <tt>hash-donor-id = SHA-512(taxid || 0x00 || salt || 0x00)</tt>. + Here, <tt>taxid</tt> is the UTF-8 string obtained by percent-decoding the <tt>taxid-enc</tt> path segment. + The verification app <bcp14>MUST</bcp14> contact the + base at the endpoint <tt>/donation-statement</tt> with the year and <tt>hash-donor-id</tt>. - The <tt>hash-donor-id</tt> must be encoded using Base 32 U Crockford + The hash of the donor taxpayer ID <tt>hash-donor-id</tt> <bcp14>MUST</bcp14> be encoded + using Base 32 U Crockford encoding <xref target="base32-U-crockford"/>. - <list style="symbols"> <t>Endpoint: /donation-statement</t> <t>Method: GET</t> -<t>Syntax: base/donation-statement/{year}/{hash-donor-id}</t> -<t>Contact: N/A</t> -<t>References: [this.I-D]</t> -</list> - + <t>Syntax: base/donation-statement/{year}/{hash-donor-id}</t> + <t>References: [this.I-D]</t> + </list> -Servers implementing the donation-statement endpoint MUST respect the -following syntax; all three fields (<tt>total-field</tt>, <tt>sig-field</tt>, <tt>pub-field</tt>) MUST be included. +Servers implementing the donation-statement endpoint +<bcp14>MUST</bcp14> respect the +following syntax; all three fields (<tt>total-field</tt>, <tt>sig-field</tt>, <tt>pub-field</tt>) <bcp14>MUST</bcp14> be included. -The amount is a string formed first of the currency (in capital +The total amount is a string formed first of the currency (in capital letters) then ":" and then the value (can be an integer or a decimal number). @@ -510,15 +524,15 @@ ALPHA = %x41-5A / %x61-7A ]]> </sourcecode> - + Example of an element of USD 100.00 : <sourcecode> <![CDATA[ { - total: "USD:100", - donation_statement_sig: "SIGNATURE", - donau_pub: "EDDSA_PUBLIC_KEY" + "total": "USD:100", + "donation_statement_sig": "SIGNATURE", + "donau_pub": "EDDSA_PUBLIC_KEY" } ]]> </sourcecode> @@ -526,56 +540,54 @@ Example of an element of USD 100.00 : </t> </section> -<section anchor="signature-total-available" title="Signature and - total are available"> + + +<section anchor="signature-total-available" + title="Verification if Signature and Total are Available"> <t> - The verification app MUST verify that the signature corresponds to + The verification app <bcp14>MUST</bcp14> verify that the signature corresponds to the claimed values. - If the information is not in the URI, the verification app MUST download the total and the signature from the - base using the GET /donation-statement/ endpoint <xref - target="get-donation-statement"/>. Otherwise, it SHOULD use the - value given in the URI. + If the information is not in the URI, the verification app <bcp14>MUST</bcp14> + download the total and the signature from the + base using the GET <tt>/donation-statement</tt> endpoint <xref + target="get-donation-statement"/>. Otherwise, it <bcp14>SHOULD</bcp14> use the + value given in the URI. The verification of the signature is done using EdDSA as specified in <xref target="RFC8032" />. - The verification MAY be done with the following instructions. The signed data is the concatenation of the following fields in network byte order (big-endian): + The verification <bcp14>MAY</bcp14> be done with the following instructions. + The signed data is the concatenation of the following fields + in network byte order (big-endian): <ul> <li>size (4 bytes): 32-bit unsigned integer with the total length of the signed data in bytes.</li> <li>purpose (4 bytes): 32-bit unsigned integer with the constant value <tt>1500</tt>.</li> <li>total value (8 bytes): integer part as an unsigned 64-bit integer.</li> <li>total fraction (4 bytes): fractional part as an unsigned 32-bit integer in units of 1/100000000.</li> - <li>currency (12 bytes): ASCII, left-aligned and zero-padded to 12 bytes.</li> - <li>donor hash H (64 bytes): <tt>H = SHA-512( UTF-8(taxid) || 0x00 || UTF-8(salt) || 0x00 )</tt>.</li> + <li>currency (12 bytes): ASCII string, left-aligned with zero-padding on the right to 12 bytes.</li> + <li>hash of donor taxpayer ID (64 bytes): <tt>hash-donor-id = SHA-512( UTF-8(taxid) || 0x00 || UTF-8(salt) || 0x00 )</tt>.</li> <li>year (4 bytes): 32-bit unsigned integer (the donation year).</li> </ul> - -</t> + </t> </section> -<section anchor="signature" title="Signature of the donation statement "> + +<section anchor="signature" + title="Creating Donation Statement Signatures"> <t> The server signing the donation statement <bcp14>MUST</bcp14> use the Sign(d,message) procedure implemented as defined in <xref target="RFC8032" />. </t> - <figure anchor="figure_signature_data" title="The binary representation of the data to sign"> - <artwork name="" type="" align="left" alt=""><![CDATA[ -0 -]]></artwork> - </figure> - - - - <t> - The signature over the public key covers a 32-bit pseudo header - conceptually prefixed to the EXPIRATION and BDATA fields. - The wire format is illustrated - in <xref target="figure_rrsigwithpseudo"/>. - </t> - <figure anchor="figure_rrsigwithpseudo"> - <name>The Wire Format Used for Creating the Signature of the RRBLOCK</name> - <artwork name="" type="" alt=""> + <t> + The signature over the public key covers a 32-bit pseudo header + conceptually prefixed to the donation data fields. + The wire format is illustrated + in <xref target="figure_donausigwithpseudo"/>. + </t> + <figure anchor="figure_donausigwithpseudo"> + <name>The Format for Creating Donation Statement Signatures</name> + <artwork name="" type="" alt=""> 0 8 16 24 32 40 48 56 +-----+-----+-----+-----+-----+-----+-----+-----+ | SIZE | PURPOSE (1500) | @@ -592,71 +604,81 @@ Example of an element of USD 100.00 : +-----+-----+-----+-----+-----+-----+-----+-----+ | YEAR | +-----+-----+-----+-----+ - </artwork> - </figure> - <dl newline="false"> - <dt>SIZE:</dt> - <dd> - A 32-bit value containing the length of the signed data in bytes - in network byte order. - </dd> - <dt>PURPOSE:</dt> - <dd> - A 32-bit signature purpose flag in network byte order. The value of this - field <bcp14>MUST</bcp14> be 1500. It defines the context in which - the signature is created so that it cannot be reused in other parts - of the protocol that might include possible future extensions. - The value of this field corresponds to an entry in the - GANA "GNUnet Signature Purposes" registry <xref target="GANA"/>. - </dd> - <dt>TOTAL value:</dt> - <dd> - The integer part of the total value. Unsigned integer containing the integer part of the value for the total. It is represented on 64 bits value (in big endian), - </dd> - <dt>TOTAL fraction:</dt> - <dd> - The fractional part of the total value is represented by an unsigned integer on 32 bits (also in big endian notation). It represents the fractional part of the value in 1/100000000th of the base unit. - </dd> - <dt>TOTAL currency</dt> - <dd> - A string representing the currency. ASCII, left-aligned and zero-padded to exactly 12 bytes. - </dd> - <dt>HASH:</dt> - <dd>The SHA512 hash code for the donor ID.</dd> - <dt>YEAR:</dt> - <dd>The year on a 32 bit unsigned integer in big endian.</dd> - </dl> - </section> - -<section anchor="signature-verification" title="Signature verification for a donation statement"> + </artwork> + </figure> + <dl newline="false"> + <dt>SIZE:</dt> + <dd> + A 32-bit value containing the length of the signed data in bytes + in network byte order. + </dd> + <dt>PURPOSE:</dt> + <dd> + A 32-bit signature purpose flag in network byte order. The value of this + field <bcp14>MUST</bcp14> be 1500. It defines the context in which + the signature is created so that it cannot be reused in other parts + of the protocol that might include possible future extensions. + The value of this field corresponds to an entry in the + GANA "GNUnet Signature Purposes" registry <xref target="GANA"/>. + </dd> + <dt>TOTAL value:</dt> + <dd> + The integer part of the total value. + Unsigned integer containing the integer part of the value for the total. + It is represented using a 64 bit value (in big endian). + </dd> + <dt>TOTAL fraction:</dt> + <dd> + The fractional part of the total value is represented by an + unsigned integer on 32 bits (also in big endian notation). + It represents the fractional part of the value in 1/100000000th of the base unit. + </dd> + <dt>TOTAL currency</dt> + <dd> + A string representing the currency. ASCII, left-aligned and zero-padded to exactly 12 bytes. + </dd> + <dt>HASH:</dt> + <dd>The SHA512 hash code for the donor ID.</dd> + <dt>YEAR:</dt> + <dd>The year on a 32 bit unsigned integer in big endian.</dd> + </dl> +</section> + +<section anchor="signature-verification" + title="Validating Donation Statement Signatures"> <t> -The signature verification step is taking the data presented in the figure <xref target="figure_signature_data" /> as -input. Signature MUST be verified using the EdDSA scheme described in -<xref target="RFC8032" /> the procedure is Verify(zk,message,signature). Public key and signature are given -encoded in Base 32 U Crockford MUST first be decoded to get a binary -out of it. + The signature verification step is taking the data presented in the + figure <xref target="figure_donausigwithpseudo" /> as input. + The signature <bcp14>MUST</bcp14> be verified using the EdDSA scheme described in + <xref target="RFC8032" /> the procedure is + <tt>Verify(zk,message,signature)</tt>. + Public key and signature, which are + encoded in Base 32 U Crockford in the URL, + <bcp14>MUST</bcp14> first be decoded to obtain the + respective binary value. </t> <t> - The Sign(d,message) and Verify(zk,message,signature) procedures <bcp14>MUST</bcp14> - be implemented as defined in <xref target="RFC8032" />. - </t> - + The Sign(d,message) and Verify(zk,message,signature) procedures <bcp14>MUST</bcp14> + be implemented as defined in <xref target="RFC8032" />. + </t> </section> -<section anchor="base32-U-crockford" title="Base 32 representation of - binary data"> -<t>All binary data MUST be encoded to be transmitted. For encoding, one -MUST use the Base32 U Crockford encoding. This is a variation of the -base32 encoding <xref target ="RFC4648" />. This encoding is presented -in details in the appendix of the RFC for GNU Name System <xref target="RFC9498" /> -</t> -<t> -The encoding works similarly to the standard, but uses another Base 32 -Alphabet. The new alphabet is given in the Table <xref target="figure_base32_encoding" />, below. -</t> -<figure anchor="figure_base32_encoding" title="The Base 32 Encoding Alphabet."> - <artwork name="" type="" align="left" alt="table where value beween 0 and 9 are encoded with the character corresponding to the number. Then between 10 and 31, we have all the letters expect I, L, O, U that could be missleading (OCR may not recognize them properly). Pading is the char ="><![CDATA[ +<section anchor="base32-U-crockford" + title="Base 32 Representation of Binary Data"> + <t> + All binary data <bcp14>MUST</bcp14> be encoded to be transmitted. For encoding, one + <bcp14>MUST</bcp14> use the Base32 U Crockford encoding. This is a variation of the + base32 encoding <xref target ="RFC4648" />. This encoding is presented + in detail in the appendix of the RFC for GNU Name System <xref target="RFC9498" /> + </t> + <t> + The encoding works similarly to the standard, but uses another Base 32 + Alphabet. The new alphabet is given in the Table <xref target="figure_base32_encoding" />, below. + </t> + + <figure anchor="figure_base32_encoding" title="The Base 32 Encoding Alphabet."> + <artwork name="" type="" align="left" alt="table where value between 0 and 9 are encoded with the character corresponding to the number. Then between 10 and 31, we have all the letters expect I, L, O, U that could be misleading (OCR may not recognize them properly). Padding is the char ="><![CDATA[ Value Encoding Value Encoding Value Encoding Value Encoding 0 0 9 9 18 J 27 V 1 1 10 A 19 K 28 W @@ -669,14 +691,15 @@ Value Encoding Value Encoding Value Encoding Value Encoding 8 8 17 H 26 T ]]> - </artwork> -</figure> - -<t> -To prevent optical character reading (OCR) problems, a system decoding binary data encoded with base 32 U Crockford MUST -accept the codes presented in the Table <xref target="figure_base32_decoding"/>, below. System reading a U -MUST evaluate it as a V. -</t> + </artwork> + </figure> + + <t> + To prevent optical character reading (OCR) problems, a system decoding + binary data encoded with base 32 U Crockford <bcp14>MUST</bcp14> + accept the codes presented in the Table <xref target="figure_base32_decoding"/>, below. + System reading a <tt>U</tt> <bcp14>MUST</bcp14> evaluate it as a <tt>V</tt>. + </t> <figure anchor="figure_base32_decoding" title="The Base 32 Decoding Alphabet."> <artwork name="" type="" align="left" alt=""><![CDATA[ @@ -691,20 +714,82 @@ Value Encoding Value Encoding Value Encoding Value Encoding 7 7 16 G|g 25 S|s 8 8 17 H|h 26 T|t ]]></artwork> - </figure> - + </figure> - </section> +</section> - <section anchor="appendix-test-vectors" title="Appendix. Test Vector: Verify from URI"> - <t> - This appendix shows how to verify a donation statement starting from a - received URI. Public key is fetched from the Donau base. - </t> +<section anchor="security" title="Security Considerations"> + <t> + Donau validators <bcp14>SHOULD</bcp14> support + "<tt>donau+http://</tt>"-URIs only when run in developer or debug mode + as otherwise the integrity and authenticity of the public key + cannot be assured. + </t> + <t> + Running "<tt>donau+http://</tt>"-URIs on a production server + <bcp14>MUST NOT</bcp14> be permitted, since it would be a security issue. + This scheme is intended only for testing purposes, + for instance on <tt>localhost</tt>. + </t> + <t> + Validator applications <bcp>MUST</bcp> include protections + against repeated validations of the same donation statement + with the same salt and year. Specifically, when summing up + multiple donation statements for the same taxpayer and + tax year, the <bcp>MUST</bcp> keep enough state to add + up the maximum total amounts per salt if multiple donation + statements are submitted with the same salt. + </t> +</section> - <figure> - <artwork><![CDATA[ + +<section anchor="iana" title="IANA Considerations"> + <name slugifiedName="name-iana-considerations">IANA Considerations</name> + <t> + IANA maintains the "Uniform Resource Identifier (URI) Schemes" + registry that contains an entry for the 'donau' URI scheme. IANA is + requested to update that entry to reference this document when + published as an RFC. + </t> + <dl indent="3" newline="false" spacing="normal" pn="section-9-2"> + <dt>Scheme name:</dt> + <dd> donau</dd> + <dt>Status:</dt> + <dd> provisional</dd> + <dt>URI scheme syntax:</dt> + <dd>See <xref target="syntax" format="default" sectionFormat="of" derivedContent="Section 3"/> of [This.I-D].</dd> + <dt>URI scheme semantics:</dt> + <dd>See <xref target="semantics" format="default" sectionFormat="of" derivedContent="Section 4"/> of [This.I-D].</dd> + <dt>Applications/protocols that use this scheme name:</dt> + <dd> GNU Taler</dd> + <dt>Contact:</dt> + <dd> + <t><contact fullname="Christian Grothoff"/> &lt;grothoff@gnu.org&gt;</t> + </dd> + <dt>Change controller:</dt> + <dd> + <t><contact fullname="Christian Grothoff"/> &lt;grothoff@gnu.org&gt;</t> + </dd> + <dt>References:</dt> + <dd> See <xref target="refs" format="default" sectionFormat="of" derivedContent="Section 13"/> of [This.I-D].</dd> + </dl> +</section> + + +</middle> + +<back> + + +<section anchor="appendix-test-vectors" title="Appendix. Test Vector: Verify from URI"> + <t> + This appendix shows how to verify a donation statement starting from a + received URI. Public key is fetched from the Donau base. + </t> + + <figure> + <artwork><![CDATA[ Example URI: donau://donau.test.taler.net/?year=2025&id=123%2F456%2F789&salt=AWNFDRFT0WX45W4Y32A9DJA03S1EF66GFQZ9EV5EF9JTHWZ37WR0&total=TESTKUDOS:1&sig=ED25519:B14WGS43FFPEB8JMSR6W1H8M6KH9AV33JFH376R6PM2MNH4GR24FP1C93C4ZPDG21W5WY4SASZQ4CRS427F4WJZJFZMQ5Y4HZNXGY30 @@ -719,11 +804,11 @@ Extracted fields: Fetched public key for year 2025 from https://donau.test.taler.net/keys: - pub: 2FRN2CAK9DMDWE157W6HY97RAVSP0ZCCC08X9N6JD2MK7413XXZG - ]]></artwork> - </figure> +]]></artwork> + </figure> - <t>Verification steps:</t> - <list style="numbers"> + <t>Verification steps:</t> + <list style="numbers"> <t>Input (URI):<br/> <tt>donau://donau.test.taler.net/?year=2025&amp;id=123%2F456%2F789&amp;salt=AWNFDRFT0WX45W4Y32A9DJA03S1EF66GFQZ9EV5EF9JTHWZ37WR0&amp;total=TESTKUDOS:1&amp;sig=ED25519:B14WGS43FFPEB8JMSR6W1H8M6KH9AV33JFH376R6PM2MNH4GR24FP1C93C4ZPDG21W5WY4SASZQ4CRS427F4WJZJFZMQ5Y4HZNXGY30</tt></t> <t>Parse fields:<br/> @@ -736,13 +821,13 @@ Fetched public key for year 2025 from https://donau.test.taler.net/keys: - sig (Crockford Base32, algorithm ED25519): <tt>B14WGS...XGY30</tt></t> <t>Public signing key (Crockford Base32) (from <tt>/keys</tt>):<br/> <tt>2FRN2CAK9DMDWE157W6HY97RAVSP0ZCCC08X9N6JD2MK7413XXZG</tt></t> - <t>Donor hash <tt>H</tt> = <tt>SHA-512( UTF-8(taxid) || 0x00 || UTF-8(salt) || 0x00 )</tt>:<br/> + <t>Hash of the donor taxpayer ID <tt>hash-donor-id</tt> = <tt>SHA-512( UTF-8(taxid) || 0x00 || UTF-8(salt) || 0x00 )</tt>:<br/> - length: 64 bytes<br/> - hex:<br/> <tt>4aaa1e16fc5be44842b863b1f17da39296ca7b3529a720e11aba9c8bd729f7a1e2bb0b9a39c02d271da5dd15aea66ce95be78bcaf380de19a0bdbcd8a7938f1b</tt><br/> - Crockford Base32 (for HTTP endpoints):<br/> <tt>9AN1W5QWBFJ4GGNRCERZ2ZD3JABCMYSN56KJ1R8TQAE8QNS9YYGY5ERBK8WW0B973PJXT5DEMSPEJPZ7HF5F706Y36GBVF6RMY9RY6R</tt></t> - <t>Amount encoding (<tt>TALER_AmountNBO</tt>):<br/> + <t>Total amount encoding (<tt>TALER_AmountNBO</tt>):<br/> - currency (12 bytes): <tt>"TESTKUDOS"</tt> then <tt>0x00</tt> x 3<br/> - value (uint64 BE): <tt>1</tt> -> <tt>0x0000000000000001</tt><br/> - fraction (uint32 BE): <tt>0</tt> -> <tt>0x00000000</tt></t> @@ -752,7 +837,7 @@ Fetched public key for year 2025 from https://donau.test.taler.net/keys: - [0008..0015] 8 bytes <tt>amount.value</tt>: <tt>0x0000000000000001</tt><br/> - [0016..0019] 4 bytes <tt>amount.fraction</tt>: <tt>0x00000000</tt><br/> - [0020..0031] 12 bytes <tt>amount.currency</tt>: <tt>54 45 53 54 4b 55 44 4f 53 00 00 00</tt> ("TESTKUDOS\x00\x00\x00")<br/> - - [0032..0095] 64 bytes <tt>i.hash</tt>: donor hash <tt>H</tt><br/> + - [0032..0095] 64 bytes <tt>i.hash</tt>: hash of donor taxpayer ID <tt>hash-donor-id</tt><br/> - [0096..0099] 4 bytes <tt>year</tt>: <tt>0x000007E9</tt> (2025)</t> <t>Message <tt>M</tt> (hex, 100 bytes):<br/> <tt>00000064 000005dc 0000000000000001 00000000 544553544b55444f53000000 4aaa1e16fc5be44842b863b1f17da39296ca7b3529a720e11aba9c8bd729f7a1e2bb0b9a39c02d271da5dd15aea66ce95be78bcaf380de19a0bdbcd8a7938f1b 000007e9</tt></t> @@ -766,20 +851,14 @@ Fetched public key for year 2025 from https://donau.test.taler.net/keys: - length: 32 bytes<br/> - hex:<br/> <tt>13f15131534b68de38253f0d1f24f856f3607d8c6011d4d4d268a9339023ef7f</tt></t> - <t>Verification (expected): call <tt>crypto_sign_verify_detached(sig, M, 100, pubkey)</tt>. The result MUST indicate a valid signature for this vector.</t> - <t>Negative check (optional): flip one bit of <tt>M</tt> or <tt>sig</tt> and repeat; verification MUST fail.</t> + <t>Verification (expected): call <tt>crypto_sign_verify_detached(sig, M, 100, pubkey)</tt>. The result <bcp14>MUST</bcp14> indicate a valid signature for this vector.</t> + <t>Negative check (optional): flip one bit of <tt>M</tt> or <tt>sig</tt> and repeat; verification <bcp14>MUST</bcp14> fail.</t> </list> - </section> - - - - +</section> -</middle> -<back> - <references title="Normative References"> + <references anchor="refs" title="Normative References"> &RFC2119; @@ -789,43 +868,43 @@ Fetched public key for year 2025 from https://donau.test.taler.net/keys: &RFC5234; - &RFC6234; + &RFC6234; - &RFC8032; + &RFC8032; - &RFC9498; + &RFC9498; - &RFC8905; + &RFC8905; </references> <references title="Informational References"> - &RFC4648; - - - <reference anchor="GANA" target="https://gana.gnunet.org/"> - <front> - <title>GNUnet Assigned Numbers Authority (GANA)</title> - <author><organization>GNUnet e.V.</organization> - </author> - <date month="April" year="2020" /> - </front> - </reference> - - <reference anchor="BaThesis" target="https://www.taler.net/papers/donau-thesis.pdf"> - <front> - <title>Tax-deductable Privacy-Preserving Donations</title> - <author initials="J.C." surname="Casaburi" fullname="Johannes Casaburi"> - <organization>Bern University of Applied Science, Bachelor Thesis</organization> - </author> - <author initials="L.M." surname="Matya" fullname="Lukas Matya"> - <organization>Bern University of Applied Science, Bachelor Thesis</organization> - </author> - </front> + &RFC4648; + + + <reference anchor="GANA" target="https://gana.gnunet.org/"> + <front> + <title>GNUnet Assigned Numbers Authority (GANA)</title> + <author><organization>GNUnet e.V.</organization> + </author> + <date month="April" year="2020" /> + </front> </reference> - </references> + + <reference anchor="BaThesis" target="https://www.taler.net/papers/donau-thesis.pdf"> + <front> + <title>Tax-deductable Privacy-Preserving Donations</title> + <author initials="J.C." surname="Casaburi" fullname="Johannes Casaburi"> + <organization>Bern University of Applied Science, Bachelor Thesis</organization> + </author> + <author initials="L.M." surname="Matya" fullname="Lukas Matya"> + <organization>Bern University of Applied Science, Bachelor Thesis</organization> + </author> + </front> + </reference> + </references> <!-- Change Log v00 2025-10-17 CG Initial version