Terminology¶
This protocol can be referred to as the Verifiable PayID Protocol
. It uses the following terminology.
- endpoint: either the client or the server of the connection.
- sender: individual or entity originating the transaction.
- PayID client: the endpoint that initiates PayID protocol/sending side of the transaction.
- PayID server: the endpoint that returns payment account(s) information/receiving side of the transaction (custodial or non-custodial wallets, exchanges, etc).
- receiver/PayID owner: individual or entity receiving the transaction/owner of the PayID[PayID-URI][].
The terms receiver
and PayID owner
are used interchangeably.
The key words "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 [RFC2119][] and [RFC9174][].
Motivation¶
Basic PayID protocol [PAYID-PROTOCOL][] specifies a protocol to interact with a PayID server and retrieve a payment account(s) information resource along with other meta-data corresponding to the queried PayID. The protocol relies on the underlying secure transport (TLS 1.3 [RFC8446][]) to ensure message integrity and privacy from network attackers. There are at least two assumptions in the security and privacy model of the basic PayID protocol that are less desirable.
-
Trust requirement between the PayID client and PayID server: As pointed out in the security considerations section of the [PAYID-PROTOCOL][], PayID server has full control over the contents of the response message, and may go rogue or be compromised. The PayID client has no way of knowing if the PayID server behaves maliciously. This implicit trust assumption between the PayID client and server is not ideal in the world where the information provided by the PayID server may be used by the PayID client to transmit money.
-
Privacy: Per [PAYID-PROTOCOL][], anyone can query the PayID server and retrieve the payment account(s) information corresponding to the queried PayID. The PayID server or PayID owner has no way of deploying access control mechanisms since the
identity
of the PayID client and the sender is unknown to the PayID server.
The motivation for the Verifiable PayID protocol is threefold:
-
Eliminate implicit trust assumption between the PayID client and server: While it is not possible for the protocol to prevent PayID server from acting maliciously, the best we can do is to allow for mechanisms in the protocol that enables PayID client to prove this misbehaviour to third-parties and potentially hold the PayID server legally accountable for misbehaving.
-
Enhance privacy of the PayID protocol by allowing the PayID client to share their and sender's
identity
information with the PayID server. This information could then be used to:- Give the PayID owner and/or PayID server the ability to decide if they want to share their payment account(s) information and other resources with the PayID client or the sender.
- Allow for an open standards based way for endpoints to keep verifiable records of their financial transactions, to better meet the needs of accounting practices or other reporting and regulatory requirements.
-
Ensure that if the PayID server is compromised, an attacker cannot swap a payment address in the payment account information response and redirect funds to the attacker-controlled payment network and address. Allow the PayID server or PayID owner to pre-sign
PaymentInformation
in a cold/airgapped system offline instead of online on a hot wallet. -
Allows for non-custodial service providers to run non-custodial PayID service by allowing the PayID owners to digitally sign the
PaymentInformation
resource locally on their device with their off-ledger private keys and send PayID owner'sidentity
information in the response. This information can then be used by the PayID client and sender to authenticate the PayID owner and decide if they want to proceed with the transaction.
Verifiable PayID Protocol Specification¶
The Verifiable PayID protocol is designed along the same design principles as [PAYID-PROTOCOL][].
Basic Operations¶
Following are the basic operations performed by the verifiable PayID client and PayID server to retrieve PaymentInformation
resource corresponding to PayID.
PayID Client Requesting the PaymentInformation Resource¶
When requesting the payment accounts(s) information resource per [PAYID-PROTOCOL][] that is digitally signed and requires input parameters, the PayID client uses the HTTP POST
method with path parameter payment-setup-details
with an optional payload in JSON format. We define this resource as a PaymentInformation
resource.
PayID Server Responding to the PaymentInformation Resource Request¶
Upon receiving a request for a PaymentInformation
resource that the PayID server can provide, the PayID server normally returns the requested response. However, if PayID server does not support the Verifiable PayID protocol, the PayID server MAY send back an appropriate error code (TBD) to indicate to the PayID client that the resource is available via an HTTP GET
request to an alternate URL.
JSON Payloads¶
PayID Client Request Query Body for PaymentInformation Resource¶
{
optional string identity,
optional string memo
}
identity¶
The type/value of the identity
field is TBD. We anticipate this being a mechanism for the PayID client to transmit their or the sender's identity
information to the PayID server. This information can then be used by the PayID server/PayID owner to
* Enhance privacy by exercising access control mechanisms such as authorized access via accept/deny lists, etc. for the PaymentInformation
or other resources for a PayID.
* Record-Keeping
memo¶
The type/value of the memo
field is TBD. memo
field is a placeholder to ensure protocol extensibility. e.g. for the primary use-case of making payments, the PayID client MAY send information such as amount, scale, etc. necessary to make the payment.
//TBD: The request body parameters will depend on the use-case.
PayID Server Response Body for PaymentInformation Resource Request¶
Refer to the payment account(s) information resource in [PAYID-PROTOCOL][].
SignatureWrapper¶
SignatureWrapper
is an encapsulating wrapper for any verifiable PayID protocol messages. It allows for the generation of cryptographically signed third-party verifiable proofs of the contents of the messages exchanged between the participating endpoints. We define SignatureWrapper
as JSON object with the following name/value pairs:
{
required string messageType,
required Message message,
required string publicKeyType,
required array publicKeyData,
required string publicKey,
required string signature
}
messageType¶
The value of messageType
is the message type of the signed message
. messageType
is essential for future extensibility of the protocol to include more message types. We define the following enum for message types:
enum messageType
{
PaymentInformation
}
message¶
The value of message
includes the contents of the Verifiable PayID protocol message of the type messageType
to be signed.
publicKeyType¶
The value of publicKeyType
is the Public Key Infrastructure (PKI)/identity system being used to identify the signing endpoint. e.g. X509+SHA512
means an X.509 certificate as described in [RFC5280][] and SHA512 hash algorithm used to hash the contents of message
for signing. This field defaults to empty string. We define the following publicKeyType
values. One can register more in future.
publicKeyType | Description |
---|---|
X509+SHA512 | A X.509 certificate [RFC5280][] |
pgp+SHA512 | An OpenPGP certificate |
ecdsa+SHA256 | A secp256k1 ECDSA public key [RFC6979][] [RFC8422][] |
publicKeyData¶
The value of publicKeyData
is the PKI-system/identity data used to identify the signing endpoint who creates digital signatures over the hash of the contents of the message
. e.g. in the case of X.509 certificates, it may contain one or more X.509 certificates as a list upto the root trust certificate. Defaults to empty.
publicKey¶
The value of publicKey
is the contents of the public key. Defaults to empty.
signature¶
The value of signature
is the digital signature over the hash of the contents of the message
using the private key corresponding to the public key in publicKey
. This is a proof that the message
was signed by the corresponding private key holder.
Custodial and Non-Custodial PayID Service Providers¶
We anticipate that the most common use-case for retrieving the PaymentInformation
resource is to make transactions. We can categorize the providers of such services as follows:
* Custodial wallets and exchanges: Custodial wallets and exchanges hold the private keys of their customers on their servers and essentially hold their funds. There is an implicit trust between the custodial service provider and their customers.
- Non-Custodial wallets and exchanges: Non-custodial wallets and exchanges do not store their customers’ keys on their servers. The customers hold their private keys locally on their device. [Arguably] there is a no trust requirement between the non-custodial wallets and exchanges and their customers. Since the customers hold the private keys so the wallets are not liable for any consequences coming from the lost, compromised or hacked private keys of the customers. Nor do they need their customers to trust their servers in case wallet's servers go malicious or are compromised.
Notice that the custodial and non-custodial service providers operate under different trust models. To continue operating under the same trust model, verifiable PayID requires slightly different treatment for custodial and non-custodial service providers.
Verifiable PayID Protocol for Custodial Wallets and Exchanges¶
The Verifiable PayID protocol flow is similar to that of the Basic PayID protocol [PAYID-PROTOCOL][] with the following modifications.
Sender PayID client PayID server Receiver
| | | |
|PayID, etc.| | |
|---------->| | |
| | 1.) POST /payment-setup-details request to PayID URL | |
| |--------------------------------------------------------->| |
| | 2.) 200 Ok | |
| | Signed PaymentInformation response | |
| |<---------------------------------------------------------| Optional |
| | |notification|
| | |----------->|
| | | |
Step 1: Preparing the HTTP Request to PayID URL using HTTP POST Method¶
A verifiable PayID client issues a query using the HTTP POST
method to the PayID URL with path parameter payment-setup-details
and optional body parameters as described above.
Step 2: Preparing the PaymentInformation Response¶
In response, the PayID server returns a JSON representation of the PaymentInformation
resource. PaymentInformation
resource is the signed
payment account(s) information message [PAYID-PROTOCOL][] for the payment-network and environment requested by PayID client in the request Accept
header field along with other required and optional metadata as message
field in the SignatureWrapper
.
Preparing the payment account(s) information message¶
- Set
payId
to the value of the PayID in the client query. This is a required field in the Verifiable PayID protocol. - Set
addresses
to the value as described in [PAYID-PROTOCOL][] - Optionally set
memo
to any additional information. identity
field is optional.- Optionally set
proofOfControlSignature
to the value as described in [PAYID-PROTOCOL][].
Preparing SignatureWrapper message¶
- Set
messageType
toPaymentInformation
. - Set
message
to the value of the payment account(s) information message as generated above. - Set
publicKeyType
to one of the values described in the Section above. - Set
publicKeyData
to the data corresponding to the value inpublicKeyType
. - Set
publicKey
to the value of the public key of the signing endpoint (PayID server.) - Sign the
message
using the hash algorithm and the signature scheme corresponding to the value inpublicKeyType
- Set
signature
to the result of the signature operation in the previous step.
Send the signed payment account(s) information message as PaymentInformation
response to the client.
Step 3: Parse PaymentInformation Response¶
If the PayID server returns a valid response, the response will contain one or more of the fields defined above. The PayID client will then:
- Verify the
publicKey
using the information in thepublicKeyType
andpublicKeyData
in the response. - Verify the signature retrieved from the
signature
field using the public key verified in the previous step. - Retrieve payment account(s) information message from the
message
field of thePaymentInformation
Response.
All the verification steps MUST pass. The PayID client proceeds to the next step only if the previous step passes, otherwise it generates the relevant Error message (//TBD).
Verifiable PayID Protocol for Non-Custodial Wallets and Exchanges¶
Pre-step at PayID owner's (non-custodial wallet's customer) device locally.
For each payment-network
and environment
as described in [PAYID-PROTOCOL][] that the PayID owner has a payment address for, generate the following payment account(s) information message
* Set payId
to the value of the PayID. This is a required field in the Verifiable PayID protocol.
* Set addresses
to the value as described in [PAYID-PROTOCOL][]
* Optionally set memo
to any additional information.
* identity
field is TBD.
* proofOfControlSignature
is optional described in [PAYID-PROTOCOL][] and is not required in this case.
For each payment account(s) information message, prepare SignatureWrapper
message
* Set messageType
to PaymentInformation
.
* Set message
to the value of payment account(s) information message as generated above.
* Set publicKeyType
to one of the values described in Section X.
* Set publicKeyData
to the data corresponding to the value in publicKeyType
.
* Set publicKey
to the value of the public key of the signing endpoint (PayID server.)
* Sign the message
using the hash algorithm and the signature scheme corresponding to the value in publicKeyType
* Set signature
to the result of the signature operation in the previous step.
This signed payment account(s) information message is then securely transferred to the non-custodial PayID server and stored by the PayID server as a PaymentInformation
resource.
Discussion Section on distributing PayID owner's keys¶
In this subsection, we discuss potential ways to distribute the keys of the PayID owner used to sign the message. Once we reach a consensus, it will be added to the relevant sections of this document and this subsection will be removed. Following are the two possible approaches:
identity field in payment account(s) information message¶
The following table enumerates the possible ways to share the public key of PayID owner using identity
field.
identity | Description |
---|---|
Global Identifier (GiD) [Gid][] | digital identifier |
Human Universally Unique Identifier (Human UUID) [HUUID][] | digital identifier |
Digital Identifier (DID) [DID][] | digital identifier |
Certificate | attested certificate that associates digital identifier to PayID and public key |
URL | URL for secure retrieval of public key of the PayID owner |
Public key | out-of-band pre-shared public key between PayID client and PayID owner |
-
Digital identifier: A global digital identifier that uniquely associates the
PayID owner's identity
as defined by the identifier (GiD, HUID, DID, etc.) to thePayID
andpublic key
. The PayID client can then verify thepublic key
using the digital identifier. This could be a direct retrieval of the correspondingpublic key
from a digital identity service provider if PayID is a part of that digital identifier. -
Certificate: An attested certificate that associates digital identifier such as GiD, Human UUID, DID, etc. to the
PayID
andpublic key
. -
URL: A URL for secure retrieval of
public key
of the PayID owner. -
Pre-shared public Key: The public key that has been pre-shared out-of-band between the PayID client and PayID owner.
Embed the public key of PayID owner in the PayID¶
PayID [PAYID-URI][] could support non-custodial systems with a fairly simple extension to the protocol to run non-custodial PayID servers that could not be hacked or tricked into sending money to the wrong place. The idea is to reserve the hostname pkh
for public key hashes
and support a PayID format like public_key_hash
$pkh.provider.domain. PayID client implementations would require that any PaymentInformation
resource that resulted from the PayID of that form be signed with the private key
corresponding to that public key hash
. So only a PaymentInformation
signed by the owner of the PayID would work.
The caveat is that the PayID format is not human-readable anymore. The solution is simple: the non-custodial wallets and exchanges would provide a non-human-readable PayID of the form public_key_hash
$pkh.provider.domain, but the customers may get a human-readable PayID from another trusted service providers (say from their email provider) that maps to the non-human-readable PayID they got from their non-custodial service-provider. Non-custodial service-providers could even automate this process by allowing the user to choose a mapping provider.
// Details TBD
Step 1: Preparing HTTP Request to PayID URL using HTTP POST Method¶
Same as in the previous section.
Step 2: Preparing PaymentInformation Response¶
The PayID server MUST parse the request body. The protocol does not provide specification on how the PayID server MAY use this information.
If the PayID server were to proceed, the PayID server retrieves the pre-signed PaymentInformation
response to the PayID client.
Step 3: Parsing the PaymentInformation Response¶
The PayID client follows the same verification steps as in the previous section. Details to be decided based on identity
solution.
Example Use of the Verifiable PayID Protocol¶
This section shows sample use of the Verifiable PayID protocol in several hypothetical scenarios.
Verifiable PayID Protocol by a Custodial Wallet as PayID server¶
Suppose Alice (sender) wishes to send a friend Bob (PayID owner) some XRP from a web-based wallet provider (PayID client) that Alice has an account on. Alice would log-in to the wallet provider and enter Bob's PayID (say, bob$receiver.example.com
) into the wallet UI to start the payment.
The Wallet application would first discover the PayID URL for the PayID service-provider using one of the mechanisms described in PayID discovery protocol [PAYID-DISCOVERY][].
The Wallet application would then issue an HTTPS POST request:
POST /users/bob/payment-setup-details HTTP/1.1
Host: www.receiver.example.com
Accept: application/xrpl-testnet+json
PayID-version: 1.0
{
"identity": "TBD",
"memo": "Any additional required information"
}
Bob's wallet who is a custodial PayID server wallet might respond like this:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 403
PayID-version: 1.0
Cache-Control: max-age=0
Server: Apache/1.3.11
{
"messageType" : "PaymentInformation",
"message" :
{
"payId" : "bob$receiver.example.com",
"addresses" :
[
{
"paymentNetwork" : "xrpl",
"environment" : "testnet",
"addressDetailsType" : "CryptoAddressDetails",
"addressDetails" : {
"address" : "XTVQWr6BhgBLW2jbFyqqufgq8T9eN7KresB684ZSHKQ3oDth"
}
}
],
"memo" : "Additional optional Information",
"proofOfControlSignature" :
{
"publicKey" : "sdkfhjasdvkakjnasdv",
"payId" : "bob$receiver.example.com",
"hashAlgorithm" : "SHA512",
"signature" : "9743b52063cd84097a65d1633f5c74f5"
}
}
"publicKeyType" : "X509+SHA512",
"publicKeyData": [],
"publicKey" : "00:c9:22:69:31:8a:d6:6c:ea:da:c3:7f:2c:ac:a5:af:c0:02:ea:81:cb:65:b9:fd:0c:6d:46:5b:c9:1e:9d:3b:ef...",
"signature" : "8b:c3:ed:d1:9d:39:6f:af:40:72:bd:1e:18:5e:30:54:23:35..."
}
In the above example we see that Bob's custodial PayID server wallet returned a signed X-Address on XRPL testnet identified by PayID bob$receiver.example.com
. This is because Alice's wallet asked for XRPL and testnet payment accounts corresponding to the PayID in the Accept
header.
Alice's Wallet MAY then use the payment account information to make payments.
Verifiable PayID Protocol by a Non-Custodial Wallet as PayID Server¶
Consider the same scenario as above.
Bob's wallet who is a non-custodial PayID server might respond like this:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 403
PayID-version: 1.0
Cache-Control: max-age=0
Server: Apache/1.3.11
{
"messageType" : "PaymentInformation",
"message" :
{
"payId" : "bob$receiver.example.com",
"addresses" :
[
{
"paymentNetwork" : "xrpl",
"environment" : "testnet",
"addressDetailsType" : "CryptoAddressDetails",
"addressDetails" : {
"address" : "XTVQWr6BhgBLW2jbFyqqufgq8T9eN7KresB684ZSHKQ3oDth"
}
}
],
"memo" : "Additional optional Information",
"identity" : "TBD",
}
"signature" : "TBD"
}
In the above example, the PaymentInformation
resource is a pre-signed message with the off-ledger private keys of the PayID owner Bob. Bob's non-custodial wallet retrieves this response and sends it to the PayID client.
//TODO Add example for PayID owner's public key embedded in PayID.
Security Considerations¶
This security considerations section only considers verifiable PayID clients and servers bound to implementations as defined in this document.
The security guarantees mentioned in [PAYID-PROTOCOL][] applies to the Verifiable PayID protocol. In this section, we discuss a security model for the Verifiable PayID protocol.
Fully-Malicious Adversary Model for PayID Client Wallet and Custodial Wallets and Exchanges as PayID Servers¶
While the Verifiable PayID protocol operates between a PayID client and a PayID server, there are actually four parties to any payment. The other two parties are the sender of the payment whose funds are being transferred and the PayID owner or the receiver of the payment who the sender wishes to pay.
In the current security model, there is necessarily some existing trust between the sender and the sender's wallet. The sender's wallet is holding the sender's private keys and consequently their funds before the payment is made. Similarly, there is necessarily some existing trust between the receiver and their custodial wallet since the receiver has directed that the custodial wallet receive their funds.
The Verifiable PayID protocol provides a stronger security guarantee: The ideal scenario that we strive for is that the sender should be able to hold the PayID client wallet legally accountable if the institution provably mishandles their funds. Similarly, the PayID owner/receiver should be able to hold the PayID server wallet legally accountable if their funds are mishandled. However, this mechanism requires that it be possible for either wallet to establish that it acted properly and that the other wallet acted improperly.
Of course, the preferred outcome of any payment is that nothing goes wrong and both the sender and PayID owner/receiver of the payment are satisfied that the payment took place as agreed. A less desirable outcome is that the payment cannot take place for some reason and the sender still has their money and understands why the payment cannot take place.
While the protocol cannot possibly prevent the PayID client wallet from sending the funds to the wrong address or the PayID server wallet from receiving the funds but refusing to release them to the PayID owner/receiver, it is vital that the institutions not be able to plausibly blame each other for a failure where the sender has been debited but the PayID client/wallet has not been credited.
Accordingly, the security model of the Verifiable PayID protocol permits four acceptable outcomes:
- The payment succeeds, the sender is debited, and the PayID owner/receiver is credited.
- The payment fails, the sender is not debited, and the PayID owner/receiver is not credited.
- The payment fails, the sender is debited, the PayID owner/receiver is not credited, and the sender can show that the PayID client wallet did not follow the protocol.
- The payment fails, the sender is debited, the PayID owner/receiver is not credited, and the sender can show the receiver that their PayID server wallet did not follow the protocol.
Again, the protocol cannot possibly prevent outcomes 3 or 4 because the PayID client wallet can always send the money to the wrong address and the PayID server wallet can always refuse to credit the PayID owner/receiver. It is, however, critical that the PayID client and PayID server wallets not need to trust each other to ensure that one of these four outcomes occurs and that they cannot point blame at each other.
Cryptographic Proofs¶
//TODO
Fully Compromisable Custodial PayID Server Wallet (hot/always online systems): Adding another Layer of Security.¶
The Verifiable PayID protocol's security model assumes that the online servers can be physically or remotely compromised by an adversary. These are the most attractive attack vectors. There is sufficient evidence that hot/always online systems are more vulnerable.
There are multiple cryptographic operations that the PayID server wallet MUST perform to establish secure communication channels, to generate signed messages as verifiable cryptographic proofs, etc.
These operations have very different security requirements and compromising the cryptographic keys required for these operations have different security implications.
-
High-risk impersonation attack to steal funds: If the PayID server wallet’s cryptographic keys used to sign
PaymentInformation
resource are compromised, an attacker may impersonate as the PayID server wallet and sign malicious mappings (‘Receiver's PayID → attacker controlled payment address’) to send to the PayID client wallet. This may lead to indirection of funds by the PayID client wallet to the attacker-controlled address. Therefore, it is extremely important to keep these keys safe offline. -
Lower-risk impersonation attacks: An attacker can never steal funds if only cryptographic keys used to establish secure network connection between the PayID client wallet and PayID server wallet are compromised.
These differing security implications warrant a separation of generating cryptographically signed proofs and storing the cryptographic keys used to perform these two operations. Some observations that inform us on how we can deal with this are that:
* Generating the cryptographic signatures on PaymentInformation
resource need not be an online operation. This can be performed offline in a safe, cold system with a separate set of keys,
- All other cryptographic operations need to be performed online, such as signing any additional information needed to fulfill the payment or establishing secure communication channels.
Based on these observations, we propose to maintain two separate systems (hot and cold) and two separate sets of cryptographic keys for the two operations.
We propose that the PayID client wallet and PayID server wallet SHOULD follow best practices to reduce the attack surface and be more robust.
//TODO Key Management sub-section.
Security Model for Non-Custodial PayID Server Wallets¶
In the current security model, non-custodial wallets do not store their customers’ keys on their servers. The customers hold their private keys on their device. There is a no trust requirement between the service provided by the non-custodial wallets and the customers of this service. Since the customers hold the private keys: * The wallets are not liable for any consequences coming from the lost, compromised or hacked private keys of the customers. * The non-custodial wallets do not require their customers to trust their servers in case wallets servers go malicious or are compromised.
The Verifiable PayID protocol preserves this trust model. For non-custodial PayID server wallets, this means that
- On the receiving side of the payment (as a PayID server) non-custodial wallets have no liability on their end for providing
PaymentInformation
, that is, thePayID --> Payment Address
mappings for their customers that are signed with the private key of the non-custodial PayID server wallet. The PayID owners or the customers can generate this signed mapping with their own off-ledger private key locally on their app/device. The PayID client can easily verify this signature based on the trust relationship between the sender of the payment (PayID client wallet’s customer) and the receiver (non-custodial PayID server's wallet). The non-custodial PayID server wallet has no role whatsoever. This eliminates any risk of the non-custodial PayID server wallet having lost their private keys, going malicious, or getting hacked, etc. because if this happens then their customers might lose funds.
Privacy Considerations¶
All privacy guarantees in the Privacy Considerations section of [PAYID-PROTOCOL][] apply to the Verifiable PayID protocol and further address some of the privacy issues mentioned in [PAYID-PROTOCOL][].
Access Control¶
PayID protocol MUST not be used to provide PaymentInformation
or any other resources corresponding to a PayID unless providing that data via PayID protocol by the relevant PayID server was explicitly authorized by the PayID owner. If the PayID owner wishes to limit access to information, PayID servers MAY provide an interface by which PayID owners can select which information is exposed through the PayID server interface. For example, PayID servers MAY allow PayID owners to mark certain data as public
and then utilize that marking as a means of determining what information to expose via PayID protocol. The PayID servers MAY also allow PayID owners to provide a whitelist of users who are authorized to access the specific information. In such a case, the PayID server MUST authenticate the PayID client. The additional identity
field in the PayID client query request allows for this.