ds.ov2.util
Interface APDU_Serializable

All Known Implementing Classes:
APDU_BigInteger, APDU_boolean, APDU_byte, APDU_byte_array, APDU_long, APDU_short, APDU_short_array, Bignat, Bignat_array, Host_modulus, Host_signature, Host_vector, Modulus, Resizable_buffer, Serializable_array, Signature, Vector

public interface APDU_Serializable

Interface for data types that can be sent to the card by the OV-chip protocol layer. The OV-chip protocol layer is a OV-chip protocol layer that overcomes the one-APDU restriction of Java Card RMI. In addition it can enforce that certain methods are always called in a certain order. Arguments and results (yes, the OV-chip protocol layer fixes the ridiculous one-result-limitation of Java and permits methods to return multiple results) of these methods must implement the APDU_Serializable interface.

Serialization

In the process of sending and receiving objects to and from the card the internal state of those objects is converted to and from a byte array with the methods to_byte_array and from_byte_array, respectively. The conversion into a byte array is called serialization. The reverse is sometimes called deserialization.

APDU's, which are used as transport medium, are limited to 255 bytes of data. Therefore (de-)serialization can happen in serval pieces. This applies equally well to short data types, because they might be so unlucky to lay precisely on an APDU boundary (because, for instance, the preceeding argument used just 254 bytes).

Compatibility Checks

In principle the arguments and expected results on the host side must be identical in type and size to those on the card. However, whether this type equality holds is determined by is_compatible_with at runtime, and careful cheating is permitted here. For instance, arguments of type Bignat on the card are usually represented by APDU_BigInteger on the host. With this trick the OV-chip protocol layer performs convenient data-type conversions almost for free.

The method is_compatible_with is only called on those objects that are declared as arguments or results in the relevant Protocol descriptions on the host. It is not called on the arguments that the host code actually supplies. And it is never called on the card. Therefore pure host data types, such as APDU_BigInteger or Host_modulus, do not need to put anything sensible into the body of is_compatible_with. The card only checks the size of the byte stream it receives. It does not perform any further type checks.

Consider, for an example, a method that takes a Bignat argument. There will be a Bignat object in the argument array of the relevant Protocol_step instance. When the host code calls this method via the OV-chip protocol layer it might supply an APDU_BigInteger object as argument. The method is_compatible_with is only invoked on the Bignat object with the APDU_BigInteger object as argument. It is not invoked on the APDU_BigInteger object.

(The stub code that is generated by the protocol-IDL compiler performs further type conversions. In the example of the last paragraph the host driver would supply an BigInteger as argument to the stub method. The stub method will wrap an APDU_BigInteger around it.

CPP Preprocessing
This class uses the following cpp defines: PACKAGE, PUBLIC
Execution Environment:
host, card
Author:
Hendrik Tews
Version:
$Revision: 1.12 $
Last Commit:
$Date: 2009-05-28 15:17:03 $ by $Author: tews $

Method Summary
 short from_byte_array(short len, short this_index, byte[] byte_array, short byte_index)
          Deserialization of this object.
 boolean is_compatible_with(Object o)
          Compatibility check for declared and supplied arguments and results.
 short size()
          Size in bytes necessary to send or receive this object.
 short to_byte_array(short len, short this_index, byte[] byte_array, short byte_index)
          Serialization of this object.
 

Method Detail

size

short size()
Size in bytes necessary to send or receive this object. The size is constant for the livetime of an object but might be different among different objects of the same type.

For testing purposes only it is possible to change the size of an object. This however requires a certain interplay between the objects that change their size and the protocol descriptions of the OV-chip protocol layer.

Returns:
size in bytes

is_compatible_with

boolean is_compatible_with(Object o)
Compatibility check for declared and supplied arguments and results. See the compatibility check explanations. Invoked on the declared argument or result of some Protocol_step instance with the actual argument or result as argument. Should return true precisely if the actual argument/result is considered binary compatible with the declard one. The method usually checks for type and size.

The compatibility check is done in some assertion on the host side. So if this method returns false, usually an assertion fails soon afterwards.

This method need not implement a symmetric relation. For instance some_modulus.is_compatible_with(some_host_modulus) returns true if some_modulus and some_host_modulus have the same size. However, some_host_modulus.is_compatible_with(some_modulus) always returns false, because Host_modulus objects should never appear in Protocol_step instances.

Parameters:
o - actual argument or result
Returns:
true if this (the declared argument or result) is considered binary compatible with o.

to_byte_array

short to_byte_array(short len,
                    short this_index,
                    byte[] byte_array,
                    short byte_index)
Serialization of this object. Write at most len bytes of the state of this object into the byte array byte_array starting at index byte_index. The contents of byte_array up to index byte_index -1 must not be modified. this_index bytes of the state have already been written in preceeding calls to this method. Therefore, the first byte written must be the byte with index this_index of the state of this object. If the remaining portion of the state fits into len bytes the complete state must be serialized. If it does not fit, len bytes must be written now and the remainder of the state is serialized in succeeding calls to this method with a suitably adjusted this_index argument. If this_index is 0 then serialization starts with this call.

len is at least 1, but otherwise arbitrary. It might equal the expected size of the serialized state, but it might also equal the remaining available space in byte_array. If len is greater than the number of bytes needed only the bytes needed for serialization must be written.

In total, precisely this.size() bytes must be written before complete serialization is signalled by the return value.

The return value signals wheter serialization completed (or if this method must be called again) and the actual number of bytes written. There are three possible situations, depending on the size of the remaining portion of the state of this object and the len parameter:

The remaining portion of the state fits into less then len bytes.
The complete remaining state must be written and the return value is the number of bytes written (which is strictly lesser than len).
The remaining portion of the state is larger than len bytes.
len bytes of the remaining portion of the state must be written. The return value is the number of bytes written, that is, len is returned.
The remaining portion of the state fits into precisely len bytes.
The remaining portion of the state must be serialized completely by writing len bytes. The return value is len + 1.

Parameters:
len - available space in byte_array, at most len bytes should be written into byte_array
this_index - greater than or equal to zero, at most this.size() -1, number of bytes that have already been written in preceeding calls. Serialization must continue at the byte with index this_index.
byte_array - data array to serialize the state into
byte_index - index in byte_array where the first byte must be written
Returns:
the number of bytes actually written, except for the case where serialization finished by writing precisely len bytes, in this case len + 1 is returned.

Equivalently, len is returned if serialization must continue after writing len bytes. Some x < len is returned if serialization finished by writing x bytes. len + 1 is returned if serialization finished by writing len bytes.


from_byte_array

short from_byte_array(short len,
                      short this_index,
                      byte[] byte_array,
                      short byte_index)
Deserialization of this object. Read at most len bytes of the state of this object from the byte array byte_array starting at index byte_index. The byte array byte_array must not be modified. this_index bytes of the state have already been read in preceeding calls to this method. Therefore, the first byte read must be the byte with index this_index of the state of this object. If the remaining unitialized portion of the state of this object requires more than len bytes then len bytes of the state must be read now and deserialization will continues in succeeding calls to this method with a suitably adjusted this_index argument. If this_index is 0 then deserialization starts with this call.

len is at least 1, but otherwise arbitrary. It might be equal to byte_array.length - byte_index but it could be less.

In total, precisely this.size() bytes must be read before complete deserialization is signalled by the return value.

The return value signals wheter deserialization completed (or if this method must be called again) and the actual number of bytes read from byte_array. There are three possible situations, depending on the size of the remaining uninitialized portion of the state of this object and the len parameter:

The remaining uninitialized portion requires less then len bytes.
Deserialization is completed by reading the required number of bytes. The return value is the number of bytes read (which is strictly lesser than len).
The remaining uninitialized portion of the state requires more than len bytes.
len bytes must be read now and deserialization continues in the following call to this function. The return value is the number of bytes read, that is, len is returned.
The remaining uninitialized portion of the state requires precisely len bytes.
Deserialization is finished by reading len bytes. The return value is len + 1.

Parameters:
len - number of available bytes in byte_array starting at index byte_index, at most len bytes should be read.
this_index - greater than or equal to zero, at most this.size() -1, number of bytes that have already been read in preceeding calls. Deserialization must continue at the byte with index this_index.
byte_array - data array to deserialize the state from
byte_index - index in byte_array of the first available data byte
Returns:
the number of bytes read, except for the case where deserialization finished by reading precisely len bytes, in this case len + 1 is returned.

Equivalently, len is returned if deserialization must continue after reading len bytes. Some x < len is returned if deserialization finished by reading x bytes. len + 1 is returned if deserialization finished by reading len bytes.