RFC 4154
Voucher Trading System Application Programming Interface (VTS-API)
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 Notice ๐
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 ๐ง
- 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 ๐
- 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 theVTSAgentprovides. - 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.
- 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:
- 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 ๐
- 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 ๐ง
- 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:
VTSExceptionis the superclass of all exceptions thrown by the methods in the interfaces that make up the VTS-API ๐งCannotProceedExceptiongets thrown when a trading is interrupted by network failures or other errors ๐ถ๐DocumentNotFoundExceptiongets thrown when the document associated with a voucher component cannot be found ๐FeatureNotAvailableExceptiongets thrown when the method you invoked isn't supported ๐InsufficientVoucherExceptiongets thrown when the number of vouchers is less than the number specified for trading ๐InvalidParticipantExceptiongets thrown when the specified participant cannot be located ๐ซฅInvalidStateExceptiongets thrown when the state of the session is invalid and the operation cannot proceed ๐งVTSSecurityExceptiongets 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
Full Copyright Statement โจ
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
- ietf: rfc4154 2005-09
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms