FileDocCategorySizeDatePackage
ASN1Choice.javaAPI DocAndroid 1.5 API11395Wed May 06 22:41:06 BST 2009org.apache.harmony.security.asn1

ASN1Choice

public abstract class ASN1Choice extends ASN1Type
This abstract class represents ASN.1 Choice type. To implement custom ASN.1 choice type an application class must provide implementation for the following methods: getIndex() getObjectToEncode() There are two ways to implement custom ASN.1 choice type: with application class that represents ASN.1 custom choice type or without. The key point is how a value of choice type is stored by application classes. For example, let's consider the following ASN.1 notations (see http://www.ietf.org/rfc/rfc3280.txt) Time ::= CHOICE { utcTime UTCTime, generalTime GeneralizedTime } Validity ::= SEQUENCE { notBefore Time, notAfter Time } 1)First approach: No application class to represent ASN.1 Time notation The Time notation is a choice of different time formats: UTC and Generalized. Both of them are mapped to java.util.Date object, so an application class that represents ASN.1 Validity notation may keep values as Date objects. So a custom ASN.1 Time choice type should map its notation to Date object. class Time { // custom ASN.1 choice class: maps Time to is notation public static final ASN1Choice asn1 = new ASN1Choice(new ASN1Type[] { ASN1GeneralizedTime.asn1, ASN1UTCTime.asn1 }) { public int getIndex(java.lang.Object object) { return 0; // always encode as ASN1GeneralizedTime } public Object getObjectToEncode(Object object) { // A value to be encoded value is a Date object // pass it to custom time class return object; } }; } class Validity { private Date notBefore; // choice as Date private Date notAfter; // choice as Date ... // constructors and other methods go here // custom ASN.1 sequence class: maps Validity class to is notation public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {Time.asn1, Time.asn1 }) { protected Object getObject(Object[] values) { // ASN.1 Time choice passed Data object - use it return new Validity((Date) values[0], (Date) values[1]); } protected void getValues(Object object, Object[] values) { Validity validity = (Validity) object; // pass Date objects to ASN.1 Time choice values[0] = validity.notBefore; values[1] = validity.notAfter; } } } 2)Second approach: There is an application class to represent ASN.1 Time notation If it is a matter what time format should be used to decode/encode Date objects a class to represent ASN.1 Time notation must be created. For example, class Time { private Date utcTime; private Date gTime; ... // constructors and other methods go here // custom ASN.1 choice class: maps Time to is notation public static final ASN1Choice asn1 = new ASN1Choice(new ASN1Type[] { ASN1GeneralizedTime.asn1, ASN1UTCTime.asn1 }) { public Object getDecodedObject(BerInputStream in) { // create Time object to pass as decoded value Time time = new Time(); if (in.choiceIndex==0) { // we decoded GeneralizedTime // store decoded Date value in corresponding field time.gTime = in.content; // return it return time; } else { // we decoded UTCTime // store decoded Date value in corresponding field time.utcTime = in.content; // return it return time; } } public int getIndex(java.lang.Object object) { Time time = (Time)object; if(time.utcTime!=null){ // encode Date as UTCTime return 1; } else { // otherwise encode Date as GeneralizedTime return 0; } } public Object getObjectToEncode(Object object) { Time time = (Time)object; if(time.utcTime!=null){ // encode Date as UTCTime return 1; } else { // otherwise encode Date as GeneralizedTime return 0; } } }; } So now Validity class must keep all values in Time object and its custom ASN.1 sequence class must handle this class of objects class Validity { private Time notBefore; // now it is a Time!!! private Time notAfter; // now it is a Time!!! ... // constructors and other methods go here // custom ASN.1 sequence class: maps Validity class to is notation public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {Time.asn1, Time.asn1 }) { protected Object getObject(Object[] values) { // We've gotten Time objects here !!! return new Validity((Time) values[0], (Time) values[1]); } protected void getValues(Object object, Object[] values) { Validity validity = (Validity) object; // pass Time objects to ASN.1 Time choice values[0] = validity.notBefore; values[1] = validity.notAfter; } } }
see
ASN.1

Fields Summary
public final ASN1Type[]
type
private final int[]
identifiers
Constructors Summary
public ASN1Choice(ASN1Type[] type)
Constructs ASN.1 choice type.

param
type - an array of one or more ASN.1 type alternatives.
throws
IllegalArgumentException - type parameter is invalid

        super(TAG_CHOICE); // has not tag number

        if (type.length == 0) {
            throw new IllegalArgumentException(Messages.getString("security.10E", //$NON-NLS-1$
                    getClass().getName()));
        }

        // create map of all identifiers
        TreeMap map = new TreeMap();
        for (int index = 0; index < type.length; index++) {

            ASN1Type t = type[index];

            if (t instanceof ASN1Any) {
                // ASN.1 ANY is not allowed,
                // even it is a single component (not good for nested choices)
                throw new IllegalArgumentException(Messages.getString("security.10F", //$NON-NLS-1$
                        getClass().getName())); // FIXME name
            } else if (t instanceof ASN1Choice) {

                // add all choice's identifiers
                int[][] choiceToAdd = ((ASN1Choice) t).identifiers;
                for (int j = 0; j < choiceToAdd[0].length; j++) {
                    addIdentifier(map, choiceToAdd[0][j], index);
                }
                continue;
            }

            // add primitive identifier
            if (t.checkTag(t.id)) {
                addIdentifier(map, t.id, index);
            }

            // add constructed identifier
            if (t.checkTag(t.constrId)) {
                addIdentifier(map, t.constrId, index);
            }
        }

        // fill identifiers array
        int size = map.size();
        identifiers = new int[2][size];
        Iterator it = map.keySet().iterator();
        for (int i = 0; i < size; i++) {
            BigInteger identifier = (BigInteger) it.next();

            identifiers[0][i] = identifier.intValue();
            identifiers[1][i] = ((BigInteger) map.get(identifier)).intValue();
        }

        this.type = type;
    
Methods Summary
private voidaddIdentifier(java.util.TreeMap map, int identifier, int index)

        if (map.put(BigInteger.valueOf(identifier), BigInteger.valueOf(index)) != null) {
            throw new IllegalArgumentException(Messages.getString("security.10F", //$NON-NLS-1$
                    getClass().getName())); // FIXME name
        }
    
public final booleancheckTag(int identifier)
Tests whether one of choice alternatives has the same identifier or not.

param
identifier - ASN.1 identifier to be verified
return
- true if one of choice alternatives has the same identifier, otherwise false;

        return Arrays.binarySearch(identifiers[0], identifier) >= 0;
    
public java.lang.Objectdecode(BerInputStream in)


        int index = Arrays.binarySearch(identifiers[0], in.tag);
        if (index < 0) {
            throw new ASN1Exception(Messages.getString("security.110", //$NON-NLS-1$
                    getClass().getName()));// FIXME message
        }

        index = identifiers[1][index];

        in.content = type[index].decode(in);

        // set index for getDecodedObject method
        in.choiceIndex = index;

        if (in.isVerify) {
            return null;
        }
        return getDecodedObject(in);
    
public voidencodeASN(BerOutputStream out)

        encodeContent(out);
    
public final voidencodeContent(BerOutputStream out)

        out.encodeChoice(this);
    
public abstract intgetIndex(java.lang.Object object)
TODO Put method description here

param
object - an object to be encoded
return

public abstract java.lang.ObjectgetObjectToEncode(java.lang.Object object)

public final voidsetEncodingContent(BerOutputStream out)

        out.getChoiceLength(this);