RFC 4154

Voucher Trading System Application Programming Interface (VTS-API)

๐Ÿ“… published September 2005, from ietf

RFC 4154: Voucher Trading System Application Programming Interface (VTS-API) ๐Ÿ’–

  • RFC number: 4154
  • Stream: Network Working Group
  • Authors: M. Terada (NTT DoCoMo) and K. Fujimura (NTT) ๐Ÿ‘ฉโ€๐Ÿ’ป
  • Category: Informational
  • Date: September 2005
  • Obsoletes: none listed
  • Updates: none listed

Part 1 of 6, so more is coming, bestie! ๐ŸŽ€


Status of This Memo โœจ

okay so this memo is just here to give info to the Internet community ๐Ÿ“š It does not specify an Internet standard of any kind, so it's not a spec you're forced to follow. And distribution of this memo is unlimited, so share it with everyone ๐ŸŒธ

Copyright (C) The Internet Society (2005).

IESG Note ๐Ÿšจ

okay this part is IMPORTANT, bestie, so read it twice ๐Ÿ‘€

This document is not a candidate for any level of Internet Standard. It specifies the Voucher Trading System Application Programming Interface (VTS-API), and that API assumes the VTS plug-in is trusted by its user. The application making calls to VTS-API ought to authenticate the VTS plug-in and securely bind the plug-in with the VTS provider information specified in the Voucher Component. However, this document does not specify an approach to application authentication ๐Ÿ™ˆ

the VTS-API should not be used without being augmented by an application authentication mechanism ๐Ÿ’€ that's a big deal, so don't skip it!

Abstract ๐Ÿฆ‹

This document specifies the Voucher Trading System Application Programming Interface (VTS-API), and it's giving uniform. The VTS-API lets a wallet or other application issue, transfer, and redeem vouchers in the same way no matter which VTS implementation is underneath ๐Ÿงš A VTS is a system for securely transferring vouchers, like coupons, tickets, loyalty points, and gift certificates. That process is often necessary during payment and/or delivery transactions ๐Ÿ’œ

Table of Contents ๐Ÿ“‘

   1.  Introduction .................................................  3
   2.  Processing Model .............................................  4
   3.  Design Overview ..............................................  6
   4.  Concepts .....................................................  6
   5.  Interface Definitions ........................................  8
       5.1. VTSManager ..............................................  8
            5.1.1. getParticipantRepository .........................  8
            5.1.2. getVoucherComponentRepository ....................  8
       5.2. ParticipantRepository ...................................  9
            5.2.1. lookup ...........................................  9
       5.3. Participant .............................................  9
            5.3.1. getIdentifier .................................... 10
            5.3.2. getVTSAgent ...................................... 10
       5.4. VTSAgent ................................................ 10
            5.4.1. login ............................................ 11
            5.4.2. logout ........................................... 12
            5.4.3. prepare .......................................... 12
            5.4.4. issue ............................................ 13
            5.4.5. transfer ......................................... 14
            5.4.6. consume .......................................... 15
            5.4.7. present .......................................... 16
            5.4.8. cancel ........................................... 17
            5.4.9. resume ........................................... 18
            5.4.10. create .......................................... 18
            5.4.11. delete .......................................... 19
            5.4.12. getContents ..................................... 19
            5.4.13. getSessions ..................................... 19
            5.4.14. getLog .......................................... 20
            5.4.15. addReceptionListener ............................ 20
            5.4.16. removeReceptionListener ......................... 21
       5.5. Session ................................................. 21
            5.5.1. getIdentifier .................................... 21
            5.5.2. getVoucher ....................................... 22
            5.5.3. getSender ........................................ 22
            5.5.4. getReceiver ...................................... 22
            5.5.5. isPrepared ....................................... 22
            5.5.6. isActivated ...................................... 23
            5.5.7. isSuspended ...................................... 23
            5.5.8. isCompleted ...................................... 23
       5.6. Voucher ................................................. 23
            5.6.1. getIssuer ........................................ 23
            5.6.2. getPromise ....................................... 24
            5.6.3. getCount ......................................... 24
       5.7. VoucherComponentRepository .............................. 24
            5.7.1. register ......................................... 24
       5.8. VoucherComponent ........................................ 25

            5.8.1. getIdentifier .................................... 25
            5.8.2. getDocument ...................................... 26
       5.9. ReceptionListener ....................................... 26
            5.9.1. arrive ........................................... 26
       5.10. Exceptions ............................................. 27
   6.  Example Code ................................................. 28
   7.  Security Considerations ...................................... 29
   8.  Acknowledgements ............................................. 30
   9.  Normative References ......................................... 30
   10. Informative References ....................................... 30

1. Introduction ๐ŸŽ€

okay so this document specifies the Voucher Trading System Application Programming Interface (VTS-API) ๐Ÿ’… If you want the motivation and background of the Voucher Trading System (VTS), go read Requirements for Generic Voucher Trading [VTS]. It's the backstory, and it's iconic ๐ŸŒŸ

A voucher is a logical entity that represents a certain right, and the VTS manages it logically ๐Ÿฆ‹ The issuer generates a voucher, users trade it around among themselves, and then it gets collected through the VTS. The terminology and model of the VTS are also covered in [VTS], so you can check there too โœจ

Now here's the tea ๐Ÿต VTSes can be built in different ways. A centralized VTS uses one centralized online server to store and manage all the vouchers. A distributed VTS uses per-user smartcards to keep track of the vouchers each user owns. Either way, the VTS-API lets a caller application issue, transfer, and redeem vouchers the same way regardless of which VTS implementation is running ๐Ÿ’– People have tried to make generic payment APIs before. Java Commerce Client [JCC] and Generic Payment Service Framework [GPSF] are two examples. They use a modular wallet architecture where different payment modules can be added as plug-ins, and they support both check-like and cash-like payment models ๐Ÿงš This document is inspired by those approaches, but its scope is limited to the VTS model. In that model, the cash-like payment model is assumed, and vouchers are transferred directly or indirectly between the sender (transferor) and the receiver (transferee) through the VTS. This document is not meant to support an API for SET, e-check, or other payment schemes that don't fit the VTS model ๐Ÿ™…โ€โ™€๏ธ

Unlike JCC and GPSF, which are only designed to transfer monetary values, this API can transfer a wide range of values using the XML-based Generic Voucher Language [GVL] ๐ŸŒˆ The upper application layer works out the monetary meaning of a voucher using the info described in that language. This makes the API in the voucher-transfer layer simpler and helps runtime efficiency โšก The API is described in Java language syntax in this document. Bindings for other programming languages may be finished in a future version of this document or in separate related specifications ๐Ÿ‘‘

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119]

2. Processing Model โœจ

okay so this section is the processing model, aka how the VTS-API actually gets used ๐Ÿ’… some of this part is borrowed from the Generic Voucher Language spec [GVL], so shoutout to them ๐Ÿซถ

there are a few different ways to build a VTS (voucher trading system). for discount coupons or event tickets, a smartcard-based distributed offline VTS is often preferred ๐ŸŽŸ๏ธ but for bonds or securities, a centralized online VTS is preferred ๐Ÿ“ˆ the distributed ones would use public (asymmetric) key-based or shared (symmetric) key-based cryptographic challenge-and-response protocols to trade vouchers securely ๐Ÿ” the centralized ones would use transactions that rewrite ownerships of vouchers in their database ๐Ÿ—„๏ธ so it's giving "too many moving parts," and it is impractical to define standard protocols for issuing, transferring, or redeeming vouchers at this time ๐Ÿ™ˆ

so to keep things flexible, this document assumes a modular wallet architecture ๐Ÿงฉ where multiple VTSes can be added as plug-ins. instead of specifying one standard voucher transfer protocol, two specs get standardized: the Voucher Component and the VTS-API ๐ŸŽ€ here's the vibe in Figure 1:

   Sender wallet/Issuing system      Receiver wallet/Collecting system
   +---------------------------+       +---------------------------+
   |                           |       |                           |
   |  |                    Voucher Component                    |  |
   |  |          (Specifies VTS Provider and Promise)           |  |
   |  |-------------------------------------------------------->|  |
   |  |                        |       |                        |  |
   |  |         Intention to receive and payment (option)       |  |
   |  |<- - - - - - - - - - - - - - - - - - - - - - - - - - - - |  |
   |  |                        |       |                        |  |
   |  |                        |       |                        |  |
   |  | Issue/transfer/  VTS   |       |   VTS      Register    |  |
   |  | redeem request   plug-in       |   plug-in  Listener(*1)|  |
   |  |------------------>|    |       |    |<------------------|  |
   |  | (VTS API)         |<- - - - - - - ->|         (VTS API) |  |
   |  |                   | VTS-specific    |                   |  |
   |  |                   | protocol if VTS |                   |  |
   |  |                   | is distributed  |                   |  |
   |  |  Result           |<- - - - - - - ->|       Notify(*2)  |  |
   |  |<------------------|    |       |    |------------------>|  |
   +---------------------------+       +---------------------------+

   (*1) Registration is optional.  Note also that the VTS plug-ins are
        usually pre-registered when the wallet or collecting system
        is started.

   (*2) If a listener is registered.

Figure 1. Wallet architecture with VTS plug-ins

in this setup, a VTS gives you a logical view of vouchers called a Valid Voucher Set (VVS) ๐Ÿ‘‘ it's the set that includes the vouchers <I,P,H> managed by the VTS [VTS]. a user's wallet can access (view, transfer, and redeem, the whole glow-up ๐Ÿ’–) the subset of the VVS that holds the vouchers that user owns, and it does that by talking to the VTS plug-in through the VTS-API ๐Ÿ“ฒ meanwhile, an issuing system can issue a voucher and add it to the VVS, and a collecting system can get notified about redemptions via the VTS-API ๐Ÿ””

once a sender and receiver agree on which vouchers are getting traded and which VTS to use, the issuing system or wallet system asks the matching VTS plug-in to allow the issue, transfer, or redemption transaction through the VTS-API ๐Ÿซง then the VTS logically rewrites the ownership of the vouchers on the VVS using its VTS-specific protocol. the VTS is responsible for stopping illegal stuff like forgery or reproduction, as required in [VTS] ๐Ÿšซ so the protocol includes a cryptographic challenge-and-response (in a distributed VTS) or a transactional database manipulation with adequate access controls (in a centralized VTS) ๐Ÿ”’ and finally, a completion event gets sent to the wallet systems or issuing/collecting systems โœ…

this document describes the VTS-API spec. for the Voucher Component spec, which gives the syntax and semantics for describing and interpreting what vouchers mean, go check [GVL] ๐Ÿ“–

3. Design Overview ๐ŸŒธ

we went with the following approach to specify the VTS-API ๐Ÿง 

  1. Provide an abstract and uniform API that encapsulates the VTS implementation. like, one common API works for both centralized and distributed VTSes ๐Ÿ™Œ issuers and app developers get way more freedom when picking a VTS ๐Ÿ’…
  2. To make that abstract and uniform API happen, this document introduces an interface called VTSAgent. it's associated with a holder and gives you methods to manipulate the vouchers that holder has ๐Ÿงš you access vouchers only through the methods the VTSAgent provides.
  3. Use existing standards for the VTS branding mechanism (negotiation). this document assumes that the VTS to be used for sending a voucher has been settled before the VTS-APIs get called ๐Ÿค negotiation can happen in the upper application layer using other standards (e.g., [IOTP] or [ECML]), if needed.
  4. Only support the push-type voucher transfer interface, where the transferor side starts the voucher transfer session ๐Ÿš€ a pull-type voucher transfer interface can still be built on top of the push-type VTS interface at the application level, so no stress ๐Ÿซถ

4. Concepts ๐Ÿ’œ

the VTS-API is made of the following interfaces ๐ŸŽ€ a VTS is required to implement all of them except ReceptionListener, which is meant for wallets or other apps that use the VTS ๐Ÿค“

VTSManager : the starting point for using a VTS plug-in ๐Ÿšช everything you need to manipulate vouchers can be grabbed directly or indirectly through the VTSManager. it maintains two repositories: a ParticipantRepository and a VoucherComponentRepository, both described below.

ParticipantRepository : gives you the access points to participants who are going to be trading partners ๐Ÿ“’ it maintains Participants and works like an "address book" of trading partners.

Participant : represents a participant, like an issuer, a holder, or a collector ๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘ a Participant knows how to get its corresponding VTSAgent (more on that below).

VTSAgent (extends Participant) : the access point for vouchers in the Valid Voucher Set (VVS) that the VTS logically manages ๐Ÿ—๏ธ a VTSAgent lets you manipulate vouchers its holder owns with the basic trading methods: issue, transfer, consume, and present. before calling any trading methods, the application has to create a Session (described next) ๐Ÿ’ซ

Session : represents the logical connection made by the trade ๐Ÿค a Session holds references to two Participant interfaces, the sender's and the receiver's. after trading methods get called using a Session, the Session holds a reference to the vouchers being traded.

Voucher : represents one or more vouchers where the issuer and promise parts are all the same ๐ŸŽซ a Voucher holds references to the Participant interface of whoever issued it (the issuer), and to a VoucherComponent (the promise), which is described below.

VoucherComponent : represents a Voucher Component, described in [GVL] ๐Ÿ“œ it defines the promise part of the voucher.

VoucherComponentRepository : gives you the access points of VoucherComponents ๐Ÿ“š it maintains VoucherComponents and acts as a "voucher type book" managed by the VTS. this document assumes a set of VoucherComponents has already been acquired and stored in this repository. delivering VoucherComponents is beyond the scope of this document ๐Ÿ™…โ€โ™€๏ธ they might be delivered inside the VTS from the trading partners, or acquired manually from a trusted third party (see Section 3 of [GVL]).

ReceptionListener : provides a listener function for when a VTSAgent receives a voucher, for wallets or other apps that implement this interface ๐Ÿ‘‚ (this interface may not be implemented as part of the VTS.)

5. Interface Definitions ๐ŸŽ€

the interfaces in this document live in the package named "org.ietf.vts" ๐Ÿ“ฆ wallets or other apps using this API should import that package like this:

import org.ietf.vts.*;

5.1. VTSManager ๐Ÿ‘‘

public interface VTSManager

this is the starting point for using a VTS plug-in ๐Ÿšช all the objects needed to manipulate vouchers can be directly or indirectly acquired via a VTSManager, so wallets or other apps can make the VTS available by instantiating an object that implements this interface โœจ

a class that implements the VTSManager interface must have a public default constructor (a constructor without any parameters). the VTS gives that constructor a name so the implementation class can bootstrap the interface ๐Ÿฅพ

5.1.1. getParticipantRepository ๐ŸŒท

public ParticipantRepository getParticipantRepository()

returns a repository that maintains Participants.

Returns:

the ParticipantRepository of the VTS, or null if no ParticipantRepository is available.

5.1.2. getVoucherComponentRepository ๐Ÿ“

public VoucherComponentRepository getVoucherComponentRepository()

returns a repository that maintains VoucherComponents.

Returns:

the VoucherComponentRepository of the VTS, or null if no VoucherComponentRepository is available.

5.2. ParticipantRepository ๐Ÿ“’

public interface ParticipantRepository

this gives you the access points of Participants ๐Ÿ—‚๏ธ a ParticipantRepository maintains Participants and acts as an "address book" of trading partners.

the object implementing this interface maintains Participants (or holds a reference to an object that maintains them), which are going to be trading partners ๐Ÿค

a ParticipantRepository can be either (an adaptor to) "yellow pages", which is a network-wide directory service like LDAP, or a "pocket address book", which only maintains personal acquaintances ๐Ÿ“– (very different energy, both valid ๐Ÿ’…)

5.2.1. lookup ๐Ÿ”

public Participant lookup(String id)

retrieves the participant that has the specified id.

Returns:

the participant associated with the specified id, or null if the id is null or the corresponding participant cannot be found.

5.3. Participant ๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘

public interface Participant

represents the participants, like issuers, holders, and collectors ๐ŸŽญ

this interface is used as a representation of the trade partners and issuers of vouchers. anyone can retrieve objects that implement Participants from the participant repository ๐Ÿ™Œ

5.3.1. getIdentifier ๐Ÿชช

public String getIdentifier()

returns the identifier of the participant. each participant must have a unique identifier ๐Ÿ”‘

the identifier can be used for looking up and retrieving the participant via the ParticipantRepository โœจ

the format of the identifier is implementation-specific ๐Ÿคทโ€โ™€๏ธ

Returns:

the identifier string of the participant.

5.3.2. getVTSAgent ๐Ÿงš

VTSAgent getVTSAgent()

This one hands you a VTSAgent ๐ŸŽ€ and its identifier is the same as the participant's identifier. Same person, same ID, no drama ๐Ÿ’–

Returns:

an object that implements the VTSAgent.

5.4. VTSAgent ๐Ÿ’…

public interface VTSAgent extends Participant

Okay so this is the interface that gives you contact points for getting at vouchers inside a Valid Voucher Set (VVS) that the VTS manages ๐Ÿฆ‹

Each VTSAgent is tied to a holder and lets them manage the vouchers that holder owns. The holder must be authenticated using the login() method before any other method gets called, or you'll get a VTSSecurityException. Bestie, that's a whole lockout ๐Ÿ™ˆ

Before any trading method is called (like issue(), transfer(), consume(), and present()), the app has to set up a session with the prepare() method โœจ

Network failures are a real thing, so sessions can get suspended when a voucher is sent over a network ๐Ÿ’€ Good news: they can be restarted with the resume() method. All the details on how sessions are managed are in Section 5.5 ๐ŸŒธ

Some VTSAgents won't have every trading method. A voucher collecting system doesn't need a way to issue or create vouchers, for example. If you call a method that isn't supported, the VTSAgent returns a FeatureNotAvailableException ๐Ÿซถ

5.4.1. login ๐Ÿ”

public void login(String passphrase)
       throws VTSException

This authenticates the VTSAgent ๐Ÿ” The passphrase only gets specified if the VTS needs one for authentication. Otherwise it must be null. If the VTSAgent is already logged in, nothing happens. The auth scheme is up to the implementation, and here are some examples:

  1. Vouchers live on a remote centralized server (centralized VTS) that wants a password to log in. The app can prompt the user for the password, and then the password gets handed to the VTSAgent through this method. More info is in the Implementation Notes below ๐Ÿ“
  2. Vouchers live on a remote centralized server (centralized VTS) that uses challenge-and-response authentication with smartcards the users hold. Here the passphrase may be null, since getting to the smartcard doesn't require contacting the app or user. The VTSAgent gets the challenge from the server, sends it to the smartcard (inside the VTS), and sends the smartcard's response back to the server. A PIN to unlock the smartcard may be given through this method, depending on the implementation ๐Ÿง 
  3. Each user holds their own smartcard that stores their own vouchers (distributed VTS). The passphrase may be null here because no authentication is required. A PIN to unlock the smartcard may be given, depending on the implementation ๐Ÿ’œ

Implementation Notes:

A VTS is responsible for providing secure ways for users to login(). It is strongly recommended that secure communication channels such as [TLS] be used if secret or private information is sent over networks. Fake server attacks, including the so-called MITM (man-in-the-middle), must be considered as well ๐Ÿ‘€

Throws:

  • VTSSecurityException - if authentication fails.

5.4.2. logout ๐Ÿ‘‹

public void logout()
       throws VTSException

This voids the authentication that the login() method set up ๐Ÿซ 

Once logout() is called, calling any other method (except login()) will cause a VTSSecurityException. The VTSAgent can log in again using the login() method ๐Ÿ”„

Throws:

  • VTSSecurityException - if the VTSAgent is not authenticated correctly.

5.4.3. prepare ๐ŸŽฌ

public Session prepare(Participant receiver)
       throws VTSException

This establishes the session you need before trading vouchers โœจ The trading partner who receives the vouchers is the receiver. The vouchers you want to trade get specified later, when you call a trading method.

How the session gets set up depends on the implementation. A centralized VTS might start a transaction, while a distributed VTS might get the challenge it needs from the receiver so it can make an authentic response in the trading method that follows ๐Ÿงš

If the VTSAgent can't establish a session with the specified receiver (that's a permanent error), it throws an InvalidParticipantExeption. If it can't establish one because of a network failure (that's a transient error), it throws a CannotProceedException ๐Ÿ˜ญ

Parameters:

  • receiver - the trading partner who receives vouchers.

Returns:

an established session whose state is "prepared" (see Section 5.5) ๐ŸŒˆ

Throws:

  • CannotProceedException - if the preparation of the session is aborted (e.g., network failures).
  • FeatureNotAvailableException - if the VTSAgent does not provide any trading methods.
  • InvalidParticipantException - if the specified participant is invalid.
  • VTSSecurityException - if the VTSAgent cannot be authenticated correctly.

5.4.4. issue ๐ŸŒŸ

public void issue(Session session,
                  VoucherComponent promise,
                  java.lang.Number num)
       throws VTSException

This issues vouchers ๐ŸŽ It creates the specified number of vouchers <this, promise, receiver> and adds them to the VVS. If the VTS is distributed, this method creates a "response" that matches the challenge received in the prepare() method and sends it to the receiver. The receiver was already specified when prepare() got called. If the specified number is 0, nothing happens ๐Ÿ™ƒ

The session MUST be "prepared" when this method is called ๐Ÿšจ Once the vouchers are created, the session becomes "activated". When the transaction finishes successfully, it becomes "completed". If the transaction gets interrupted abnormally (e.g., network failures), it becomes "suspended" ๐Ÿซถ

Parameters:

  • session - the session used by the issue transaction.
  • promise - the promise part of the voucher.
  • num - the number of vouchers to be issued.

Throws:

  • CannotProceedException - if the transaction cannot be successfully completed.
  • FeatureNotAvailableException - if the VTSAgent does not provide a means of issuing vouchers.
  • InvalidStateException - if the session is not "prepared".
  • VTSSecurityException - if the VTSAgent cannot be authenticated correctly.

5.4.5. transfer ๐Ÿ’ธ

public void transfer(Session session,
                     Participant issuer,
                     VoucherComponent promise,
                     java.lang.Number num)
       throws VTSException

This transfers vouchers ๐Ÿ” It rewrites the specified number of vouchers <issuer, promise, this> into <issuer, promise, receiver> in the VVS. In other words, the vouchers get deleted from the sender and stored for the receiver. Just like issue(), if the VTS is distributed, this method creates and sends the response to the receiver. The VTSAgent must have enough vouchers in the VVS. If the specified number is 0, nothing happens ๐Ÿ“

The session MUST be "prepared" when this method is called ๐Ÿšจ The session becomes "activated" once the vouchers are retrieved from the sender. It becomes "completed" when the transaction finishes successfully, or "suspended" if the transaction is interrupted abnormally (e.g., network failures) ๐ŸŒธ

If null is specified for the issuer parameter, that means "any issuer". The method then picks the vouchers to transfer from the set returned by getContents(null, promise) ๐Ÿ”

Parameters:

  • session - the session used by the transfer transaction.
  • issuer - the issuer part of the voucher, or null.
  • promise - the promise part of the voucher.
  • num - the number of vouchers to be transferred.

Throws:

  • CannotProceedException - if the transaction cannot be successfully completed.
  • FeatureNotAvailableException - if the VTSAgent does not provide a means of transferring vouchers.
  • InsufficientVoucherException - if the VTSAgent does not have a sufficient number of vouchers to transfer.
  • InvalidStateException - if the session is not "prepared".
  • VTSSecurityException - if the VTSAgent cannot be authenticated correctly.

5.4.6. consume ๐Ÿ”ฅ

public void consume(Session session,
                    Participant issuer,
                    VoucherComponent promise,
                    java.lang.Number num)
       throws VTSException

This consumes vouchers ๐Ÿ’ฅ It deletes the specified number of vouchers <issuer, promise, this> from the VVS and tells the receiver about the deletion. Like issue() and transfer(), if the VTS is distributed, a response gets created and sent to the receiver, so the receiver can get proof of the deletion ๐Ÿงพ The VTSAgent must have a sufficient number of vouchers in the VVS. If the specified number is 0, nothing happens ๐Ÿ™ˆ

The session MUST be "prepared" when this method is called ๐Ÿšจ It becomes "activated" when the vouchers are deleted. It becomes "completed" when the transaction finishes successfully, or "suspended" if the transaction gets interrupted abnormally (e.g., network failures) ๐Ÿ’…

If null is specified for the issuer parameter, that means "any issuer". The method then picks the vouchers to consume from the set returned by getContents(null, promise) โœจ

Parameters:

  • session - the session used by the consume transaction.
  • issuer - the issuer part of the voucher, or null.
  • promise - the promise part of the voucher.
  • num - the number of vouchers to be consumed.

Throws:

  • CannotProceedException - if the transaction cannot be successfully completed.
  • FeatureNotAvailableException - if the VTSAgent does not provide a means of consuming vouchers.
  • InsufficientVoucherException - if the VTSAgent does not have a sufficient number of vouchers to consume.
  • InvalidStateException - if the session is not "prepared".
  • VTSSecurityException - if the VTSAgent cannot be authenticated correctly.

5.4.7. present ๐ŸŽ€

public void present(Session session,
                    Participant issuer,
                    VoucherComponent promise,
                    java.lang.Number num)
       throws VTSException

okay bestie, this one is the "show me your receipts" method ๐Ÿ’…. It presents vouchers: the sender shows the receiver that they have the specified number of <issuer, promise, this> vouchers sitting in the VVS. Nothing actually gets changed in the VVS, it's just a flex ๐Ÿฆ‹. The response still goes to the receiver, and consume() is used too, so the VTS can be proven to have been distributed โœจ. The VTSAgent must have enough vouchers in the VVS. And if the number is 0, nothing happens, no drama ๐ŸŒธ.

The session MUST be "prepared" when this method is called ๐Ÿ”ฅ. The session becomes "activated" once the vouchers are retrieved. From there it's either "completed" when the whole transaction goes through, or "suspended" if it gets interrupted abnormally (like network failures, ugh ๐Ÿ’€).

If you pass null for the issuer, that means "any issuer" ๐ŸŒˆ. The method then picks the vouchers to present from whatever getContents(null, promise) returns.

Parameters:

  • session - the session used by the present transaction.
  • issuer - the issuer part of the voucher, or null.
  • promise - the promise part of the voucher.
  • num - the number of the voucher to be presented.

Throws:

  • CannotProceedException - if the transaction cannot be successfully completed.
  • InsufficientVoucherException - if the VTSAgent does not have a sufficient number of vouchers to present.
  • InvalidStateException - if the session is not "prepared".
  • FeatureNotAvailableException - if the VTSAgent does not provide a means of presenting vouchers.
  • VTSSecurityException - if the VTSAgent cannot be authenticated correctly.

5.4.8. cancel ๐Ÿ™ˆ

public void cancel(Session session)
       throws VTSException

this is how you release a session ๐Ÿซถ. "Prepared" sessions MUST be canceled, no exceptions, bestie ๐Ÿ’€. An implementation MAY be permitted to cancel "activated" or "suspended" sessions too, so it depends on the implementation ๐Ÿงš.

Throws:

  • InvalidStateException - if the state of the session cannot be canceled.
  • VTSSecurityException - if the VTSAgent cannot be authenticated correctly.

5.4.9. resume โญ

public void resume(Session session)
       throws VTSException

this restarts a session that got paused ๐Ÿฆ‹. Only "suspended" sessions can be resumed, that's the rule. The session goes straight back to "activated" right away, and then it either ends up "completed" when the transaction succeeds, or "suspended" again if it gets interrupted abnormally (network failures again, the villain of this whole RFC ๐Ÿ˜ญ).

Throws:

  • CannotProceedException - if the transaction cannot be successfully completed.
  • InvalidStateException - if the session is not "suspended".
  • VTSSecurityException - if the VTSAgent cannot be authenticated correctly.

5.4.10. create ๐Ÿ“

public void create(VoucherComponent promise, java.lang.Number num)
       throws VTSException

this one makes new vouchers where the issuer is the VTSAgent itself ๐Ÿ‘‘. It creates the specified number of <this, promise, this> vouchers and adds them to the VVS. Zero means nothing happens โœจ.

Throws:

  • FeatureNotAvailableException - if the VTSAgent does not provide a means of creating vouchers.
  • VTSSecurityException - if the VTSAgent cannot be authenticated correctly.

5.4.11. delete ๐Ÿ—‘๏ธ

public void delete(Participant issuer, VoucherComponent promise,
                   java.lang.Number num)
       throws VTSException

the opposite energy: this deletes the specified number of <issuer, promise, this> vouchers from the VVS ๐Ÿ’”. The VTSAgent must have enough of them in the VVS, and again, a number of 0 means nothing gets done ๐ŸŒธ.

Throws:

  • InsufficientVoucherException - if the VTSAgent does not have a sufficient number of vouchers to delete.
  • VTSSecurityException - if the VTSAgent cannot be authenticated correctly.

5.4.12. getContents ๐Ÿ’œ

public java.util.Set getContents(Participant issuer,
                                 VoucherComponent promise)
       throws VTSException

this gives you back the set of vouchers where both the issuer and the promise match what you passed in ๐Ÿ”. Passing null for the issuer or the promise means "any issuer" or "any promise", respectively. If you pass null for both, you get every voucher the holder owns from the VVS, basically the whole wardrobe ๐Ÿ‘—โœจ.

Returns:

  • the set of vouchers held by the holder of the VTSAgent.

Throws:

  • VTSSecurityException - if the VTSAgent cannot be authenticated correctly.

5.4.13. getSessions ๐Ÿงพ

public java.util.Set getSessions()
       throws VTSException

this returns the set of incomplete sessions that the VTSAgent prepared. Basically the "still in progress" pile ๐ŸŒ€.

Returns:

  • the set of sessions prepared by the VTSAgent that are not yet completed.

Throws:

  • VTSSecurityException - if the VTSAgent cannot be authenticated correctly.

5.4.14. getLog ๐Ÿ“œ

public java.util.Set getLog()
       throws VTSException

this returns the set of completed sessions that the VTSAgent either prepared or received, so it's basically the trading diary ๐Ÿ“–. A VTS may eventually delete old logs, which means the full log might not come back. How much log the VTSAgent keeps is implementation-specific, so don't count on a specific amount ๐Ÿคทโ€โ™€๏ธ.

Returns:

  • the set of completed sessions prepared or received by the VTSAgent.

Throws:

  • VTSSecurityException - if the VTSAgent cannot be authenticated correctly.

5.4.15. addReceptionListener ๐Ÿ‘‚

public void addReceptionListener(ReceptionListener l)
       throws VTSException

this adds a ReceptionListener to the listener list ๐ŸŽง. Once l is registered this way, l.arrive() gets called every time the VTSAgent receives a voucher. Passing null does nothing at all โœจ.

Throws:

  • VTSSecurityException - if the VTSAgent cannot be authenticated correctly.

5.4.16. removeReceptionListener ๐Ÿšช

public void removeReceptionListener(ReceptionListener l)
       throws VTSException

the undo button for the one above ๐Ÿซ . It removes a ReceptionListener from the listener list. If the listener is null or was never registered, nothing happens.

Throws:

  • VTSSecurityException - if the VTSAgent cannot be authenticated correctly.

5.5. Session ๐ŸŒธ

public interface Session

this represents the logical connection that the trade sets up ๐Ÿ”—. Sessions get established by VTSAgent#prepare().

A session has four states: prepared, activated, suspended, and completed ๐ŸŒˆ. It starts out "prepared", and it becomes "activated" right away whenever any of the trading methods of VTSAgent gets called. An "activated" session becomes "completed" once that trading method succeeds. If the trading method fails in a transient way (like a network failure), the session becomes "suspended". Suspended sessions can be re-"activated" and restarted by calling VTSAgent#resume() ๐Ÿ”.

A completed session might disappear from the VTSAgent. When that happens, the GC collects it, unless some other objects are still holding a reference to it ๐Ÿ—‘๏ธ.

5.5.1. getIdentifier ๐Ÿชช

public String getIdentifier()

this returns the identifier of the session ๐Ÿ†”. How the identifier is generated is implementation-specific. An implementation may use a transaction ID as the identifier of the session.

Returns:

  • the string of the identifier of the session.

5.5.2. getVoucher ๐ŸŽŸ๏ธ

public Voucher getVoucher()

this returns the voucher being traded in the session, or null if the session has not been activated yet ๐Ÿ•Š๏ธ.

Returns:

  • the voucher to be traded, or null if the state of the session is "prepared".

5.5.3. getSender ๐Ÿ“ค

public Participant getSender()

this returns the sender of the session, meaning the creator who prepared it ๐Ÿ’Œ.

Returns:

  • the sender of the session.

5.5.4. getReceiver ๐Ÿ“ฅ

public Participant getReceiver()

this returns the receiver of the session, which is the participant that was specified when the session was prepared through the VTSAgent#prepare() method ๐ŸŽฏ.

Returns:

  • the receiver of the session.

5.5.5. isPrepared โœ…

public boolean isPrepared()

this checks whether the session is "prepared" ๐Ÿ”.

Returns:

  • true if the session is in the "prepared" state, otherwise, false.

5.5.6. isActivated โšก

public boolean isActivated()

this checks whether the session is "activated" ๐Ÿ”ฅ.

Returns:

  • true if the session is in the "activated" state, otherwise, false.

5.5.7. isSuspended โธ๏ธ

public boolean isSuspended()

this checks whether the session is "suspended" ๐Ÿ˜ด.

Returns:

  • true if the session is in the "suspended" state, otherwise, false.

5.5.8. isCompleted ๐Ÿ

public boolean isCompleted()

this checks whether the session is "completed" ๐Ÿ‘.

Returns:

  • true if the session is in the "completed" state, otherwise, false.

5.6. Voucher ๐ŸŽซ

public interface Voucher

this represents the voucher(s) described in [VTS] ๐Ÿ’–. An object implementing this interface can stand for more than one voucher, as long as the issuer part and the promise part of all those vouchers are the same.

5.6.1. getIssuer ๐Ÿง‘โ€๐ŸŽค

public Participant getIssuer()

this returns the issuer part of the voucher(s) ๐Ÿท๏ธ.

Returns:

  • the participant who issued the voucher(s).

5.6.2. getPromise ๐Ÿค

public VoucherComponent getPromise()

this returns the promise part of the voucher(s) ๐Ÿ“.

Returns:

  • the voucher component that defines the promise of the voucher.

5.6.3. getCount ๐Ÿ”ข

public java.lang.Number getCount()

this returns how many voucher(s) there are ๐Ÿงฎ.

Returns:

  • the positive (>0) number of the voucher(s).

5.7. VoucherComponentRepository ๐Ÿ—‚๏ธ

public interface VoucherComponentRepository

this maintains VoucherComponents ๐Ÿ“š. An object implementing VoucherComponentRepository gives you a way to retrieve the voucher components that are the promises of vouchers in the VVS ๐Ÿ’ซ.

Before a voucher gets issued, its promise must be registered with this repository ๐Ÿšจ. The repository can be a network-wide directory service, or personal storage like the ParticipantRepository. Pick whichever vibe fits your network ๐ŸŒ.

5.7.1. register ๐Ÿ–Š๏ธ

public VoucherComponent register(org.w3c.dom.Document document)

this creates a voucher component that's associated with the specified DOM object, and then registers that voucher component with the repository ๐Ÿ“ฅ. A voucher component of any voucher that's about to be issued must be registered using this method, no skipping ๐Ÿ™…โ€โ™€๏ธ.

If the specified document is null, or its syntax doesn't conform to the VTS, nothing is performed and the method returns null ๐Ÿฅ€. If the specified DOM object has already been registered, the method returns the registered voucher component, and no new voucher component gets created in that case โ™ป๏ธ.

Returns:

  • a registered voucher component associated with the specified document, or null if the document is null or has wrong syntax.

5.8. VoucherComponent

Okay bestie, this is the voucher component ๐Ÿ’… It's the bit that holds the promise of the voucher, meaning what you can claim in exchange for redeeming it ๐ŸŽ€

public interface VoucherComponent

Each VoucherComponent object has its own unique identifier and is linked to an XML document that describes the promise made by the issuer of the voucher. For example, goods or services can be claimed in exchange for redeeming the voucher ๐Ÿ›๏ธ

This interface can work as sort of a "smart pointer" to the XML document ๐Ÿงš An implementation may hold a reference to a voucher component repository instead of the voucher component itself, and it may fetch the document dynamically from that repository when the getDocument() method is called. So lazy, but in a good way ๐Ÿฆ‹

5.8.1. getIdentifier

public String getIdentifier()

This returns the identifier of the voucher component ๐Ÿ”‘ Each voucher component must have a unique identifier, and the identifier may be used to check whether two voucher components are equivalent.

The format of the identifier is up to the implementation, but it is RECOMMENDED that the hash value of the voucher component be included in the identifier so uniqueness is assured ๐Ÿ”’ To generate that hash value, it is desirable to use a secure hash function (for example, [SHA-1]) and to apply a canonicalization function (for example, [EXC-C14N]) before hashing. This keeps insignificant format changes to the voucher component, like line breaks or character encoding, from making a difference ๐ŸŒธ

Returns:

the identifier string of the voucher component.

5.8.2. getDocument

public org.w3c.dom.Document getDocument()

This returns a Document Object Model [DOM] representation of the document that was associated with the voucher component by the VoucherComponentRepository#register() method ๐Ÿ“„

The DOM object can be fetched from a VoucherComponentRepository on demand, so the VoucherComponent doesn't have to keep a reference to it all the time. Efficient queen behavior ๐Ÿ‘‘

The VTS must guarantee that the getDocument method will eventually return the DOM object, provided that the voucher associated with the corresponding voucher component exists in the VVS. No dropping the ball here ๐Ÿ’…

Returns:

a DOM representation of the document associated with the voucher component.

Throws:

DocumentNotFoundException - if the associated DOM object cannot be retrieved. ๐Ÿ˜ญ

5.9. ReceptionListener

public interface ReceptionListener extends java.util.EventListener

This is a listener interface that gets notified when a VTSAgent has received a voucher ๐Ÿ“ฌ

When a voucher arrives at the VTSAgent, the VTSAgent invokes the arrive() method of each registered ReceptionListener. A ReceptionListener can get a Session object, which holds information about the received voucher and about the sender of that voucher ๐Ÿฆ‹

This interface is meant to let a wallet know that "You have new vouchers" ๐ŸŽ€ So it may be implemented by wallets or other applications that use VTS. Main character notification energy ๐Ÿ””

5.9.1. arrive

public void arrive(Session session)

This gives notice that a voucher has arrived ๐ŸŽ‰

Once the listener is registered to a VTSAgent (using the VTSAgent#addReceptionListener() method), the VTSAgent calls this method every time it receives a voucher. The specified session is equivalent to the session the sender used to trade the voucher. By the time this method is called, the state of the session is "completed" โœ…

5.10. Exceptions

Here's the exception family tree ๐ŸŒณ

  java.lang.Exception
    +-- VTSException
        +-- CannotProceedException
        +-- DocumentNotFoundException
        +-- FeatureNotAvailableException
        +-- InsufficientVoucherException
        +-- InvalidParticipantException
        +-- InvalidStateException
        +-- VTSSecurityException

Now the individual exceptions, each with its own vibe:

  • VTSException is the superclass of all exceptions thrown by the methods in the interfaces that make up the VTS-API ๐Ÿงƒ
  • CannotProceedException gets thrown when a trading is interrupted by network failures or other errors ๐Ÿ“ถ๐Ÿ’€
  • DocumentNotFoundException gets thrown when the document associated with a voucher component cannot be found ๐Ÿ”
  • FeatureNotAvailableException gets thrown when the method you invoked isn't supported ๐Ÿ™ˆ
  • InsufficientVoucherException gets thrown when the number of vouchers is less than the number specified for trading ๐Ÿ“
  • InvalidParticipantException gets thrown when the specified participant cannot be located ๐Ÿซฅ
  • InvalidStateException gets thrown when the state of the session is invalid and the operation cannot proceed ๐Ÿšง
  • VTSSecurityException gets thrown when authentication fails, or when a method that requires authentication in advance is called without authentication ๐Ÿ”

6. Example Code

Time for the examples, the fun part ๐Ÿงšโœจ

First up, issuing a voucher ๐ŸŽŸ๏ธ

// Issue a voucher

VTSManager vts = new FooVTSManager();
ParticipantRepository addrBook = vts.getParticipantRepository();
VoucherComponentRepository vcr = vts.getVoucherComponentRepository();

Participant you = addrBook.lookup("http://example.org/foo");
  // looks up a trading partner identified as
  // "http://example.org/foo".
VTSAgent me = addrBook.lookup("myName").getVTSAgent();
  // a short-cut name may be used if VTS implementation allows.

VoucherComponent promise = vcr.register(anXMLVoucherDocument);
  // registers a voucher component that corresponds to the voucher
  // to be issued.

try {
  me.login();
    // sets up the issuer's smartcard (assuming distributed VTS).
  s = me.prepare(you);
    // receives a challenge from the partner.
  me.issue(s, promise, 1);
    // sends a voucher using the received challenge.
  me.logout();
} catch (VTSException e) {
    // if an error (e.g., a network trouble) occurs...
  System.err.println("Sorry.");
  e.printStackTrace();
    // this example simply prints a stack trace, but a real wallet
    // may prompt the user to retry (or cancel).
}

Next, transferring all of my vouchers in one go ๐Ÿ’ธ

// Transfer all my vouchers

VTSManager vts = new FooVTSManager();
ParticipantRepository addrBook = vts.getParticipantRepository();

Participant you = addrBook.lookup("8f42 5aab ffff cafe babe...");
  // some VTS implementations would use a hash value of a public key
  // (aka fingerprint) as an identifier of a participant.
VTSAgent me = addrBook.lookup("myName").getVTSAgent();
try {
  me.login();
  Iterator i = me.getContents(null, null).iterator();

  while (i.hasNext()) {
    Voucher v = (Voucher) i.next();
    s = me.prepare(you);
    me.transfer(s, v.getIssuer(), v.getPromise(), v.getCount());
  }

  me.logout();
} catch (VTSException e) {
  System.err.println("Sorry.");
  e.printStackTrace();
}

And last but not least, a "biff"-style incoming voucher notifier ๐Ÿ””๐Ÿ’œ

// Register an incoming voucher notifier (biff)

VTSManager vts = new FooVTSManager();

ParticipantRepository addrBook = vts.getParticipantRepository();
VTSAgent me = addrBook.lookup("myName").getVTSAgent();

ReceptionListener listener = new ReceptionListener() {
  public void arrive(Session s) {
    System.out.println("You got a new voucher.");
  }
};

try {
  me.login();
  me.addReceptionListener(listener);
  me.logout();
} catch (VTSException e) {
  System.err.println("Sorry.");
  e.printStackTrace();
}

7. Security Considerations

This part is serious, bestie ๐Ÿšจ Security is very important for trading vouchers. VTS implementations are responsible for preventing illegal acts upon vouchers (as described in [VTS]). They're also responsible for preventing malicious access from invalid users and fake server attacks, including man-in-the-middle attacks ๐Ÿ•ต๏ธโ€โ™€๏ธ

The means to achieve these requirements are not specified in this document, because they depend on the VTS implementation. However, securing communication channels (for example, using TLS) between client VTS plug-ins and the central server in a centralized VTS (as described in 5.4.1 login()), and applying cryptographic challenge-and-response techniques in a distributed VTS, are likely to be helpful and are strongly recommended for building a secure VTS ๐Ÿ”๐Ÿ’–

This document assumes that the VTS plug-in is trusted by its user. The caller application of a VTS should authenticate the VTS plug-in and bind it securely using the VTS Provider information specified in the Voucher Component. This document does not specify any application authentication scheme, and it is assumed that other related standards will specify one. Until various VTS systems are deployed, it is enough to manually check and install VTS plug-ins, the same way you would with other downloaded applications ๐Ÿ›ก๏ธ

8. Acknowledgements

Huge thanks to the following persons, listed in alphabetic order, who contributed substantially to the material herein ๐Ÿซถ

  • Donald Eastlake 3rd
  • Iguchi Makoto
  • Yoshitaka Nakamura
  • Ryuji Shoda

9. Normative References

  • [DOM]: V. Apparao, S. Byrne, M. Champion, S. Isaacs, I. Jacobs, A. Le Hors, G. Nicol, J. Robie, R. Sutor, C. Wilson, and L. Wood. "Document Object Model (DOM) Level 1 Specification", W3C Recommendation, October 1998, <http://www.w3.org/TR/1998/REC-DOM-Level-1-19981001/>
  • [GVL]: Fujimura, K. and M. Terada, "XML Voucher: Generic Voucher Language", RFC 4153, September 2005.
  • [RFC2119]: Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.

10. Informative References

  • [ECML]: Eastlake 3rd, D., "Electronic Commerce Modeling Language (ECML) Version 2 Specification", RFC 4112, June 2005.
  • [EXC-C14N]: J. Boyer, D. Eastlake, and J. Reagle, "Exclusive XML Canonicalization Version 1.0", W3C Recommendation, July 2002, <http://www.w3.org/TR/2002/REC-xml-exc-c14n-20020718/>
  • [GPSF]: G. Lacoste, B. Pfitzmann, M. Steiner, and M. Waidner (Eds.), "SEMPER - Secure Electronic Marketplace for Europe," LNCS 1854, Springer-Verlag, 2000.
  • [IOTP]: Burdett, D., "Internet Open Trading Protocol - IOTP Version 1.0", RFC 2801, April 2000.
  • [JCC]: T. Goldstein, "The Gateway Security Model in the Java Electronic Commerce Framework", Proc. of Financial Cryptography '97, 1997.
  • [SHA-1]: Department of Commerce/National Institute of Standards and Technology, "FIPS PUB 180-1. Secure Hash Standard. U.S.", <http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf>
  • [TLS]: Dierks, T. and C. Allen, "The TLS Protocol Version 1.0", RFC 2246, January 1999.
  • [VTS]: Fujimura, K. and D. Eastlake, "Requirements and Design for Voucher Trading System (VTS)", RFC 3506, March 2003.

Authors' Addresses

Masayuki Terada
NTT DoCoMo, Inc.
3-5 Hikari-no-oka, Yokosuka-shi, Kanagawa, 239-8536 JAPAN

Phone: +81-(0)46-840-3809
Fax:   +81-(0)46-840-3705
EMail: te@rex.yrp.nttdocomo.co.jp


Ko Fujimura
NTT Corporation
1-1 Hikari-no-oka, Yokosuka-shi, Kanagawa, 239-0847 JAPAN

Phone: +81-(0)46-859-3053
Fax:   +81-(0)46-859-1730
EMail: fujimura.ko@lab.ntt.co.jp

okay so the copyright bit ๐Ÿ’… this is "Copyright (C) The Internet Society (2005)" ๐ŸŽ€ and it's subject to the rights, licenses and restrictions in BCP 78 ๐Ÿ“œ except that the authors keep all their rights, so nobody's losing their claim on the work ๐Ÿ’œ

the disclaimer is super serious ๐Ÿ˜ญ the document and info in it are provided "AS IS", and the contributor, the org they represent or sponsor (if any), the Internet Society, and the IETF all disclaim ALL WARRANTIES, EXPRESS OR IMPLIED ๐Ÿ™ˆ that includes no warranty that using the info won't infringe any rights, and no implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE ๐Ÿ’€ translation: don't come crying to us lol ๐Ÿซถ


Intellectual Property

the IETF is staying neutral here ๐ŸŒธ it doesn't take a position on whether any IPR (Intellectual Property Rights) or other claimed rights are valid or how wide they are, or whether a license for them is even available ๐Ÿฆ‹ it also doesn't say it went out and checked for any such rights itself ๐Ÿ™ˆ if you want the rules on rights in RFC docs, go read BCP 78 and BCP 79 โœจ

the IPR disclosures sent to the IETF Secretariat, any promised licenses, and the results of trying to get a general license or permission for implementers or users are all findable in the IETF on-line IPR repository at http://www.ietf.org/ipr ๐Ÿ”ฅ

and the IETF is literally begging anyone who knows about copyrights, patents, patent applications, or other proprietary rights that might cover tech needed to implement this standard to tell them ๐Ÿฅน send it to ietf-ipr@ietf.org ๐Ÿ’– (yes, the hyphen is part of the address, it's split as "ietf-" and "ipr" across a line break in the original, so the real address is ietf-ipr@ietf.org) ๐Ÿงš


Acknowledgement

the RFC Editor function is currently funded by the Internet Society ๐ŸŒˆ so shoutout to them for keeping the lights on ๐Ÿ’…โœจ

๐Ÿ“ฆ where this page comes from