package de.persosim.simulator.tlv;
/**
* This class implements TLV data objects with primitive encoding, i.e. TLV
* data objects that in their data field may only contain plain byte sequences
* if any.
*
* Tag field: All access to this element must be committed through methods
* provided by this object. If constructed or set the field must not be set
* directly as reference to the provided object but to a clone. Accordingly any
* getter must also return a clone of this field.
*
* This behavior e.g. is to prevent anyone from converting primitive encoding to
* constructed by merely modifying the respective bit.
*
* Length field: References to this object do not need to be protected. When
* asked for its length field the object first checks whether any length field
* has been set at all. If a length field has been set it checks whether its
* encoded value matches the actual length of the value field. If so, the length
* field is returned as is. Otherwise the default DER encoding of the actual
* length of the value field is returned. In case an invalid length has been set
* on purpose, checks can explicitly be disabled. This is flagged within the
* object. If a flagged object is asked for its length field, it returns the set
* length field without any checks. If no length field is set, it will be
* computed and returned as if the flag had not been set.
*
* This behavior saves costs for strict access control on length or value
* fields.
*
* Tag field: Analogous to the length field, the value field may also be
* accessed freely. All problems that may arise from this are dealt by the way
* the length field is determined.
*
* @author slutters
*
*/
public class PrimitiveTlvDataObject extends TlvDataObject {
protected TlvValuePlain tlvValuePlain;
/*--------------------------------------------------------------------------------*/
/**
* Constructor for a TLV data object with primitive encoding based on a range
* from an array of raw bytes.
* The defined range must contain at least the whole TLV data object.
* The first byte of the range must also be the first byte of the TLV data object.
* The last byte of the range is not expected to also be the last byte of the TLV data
* object and may lay outside of the array.
*
* @param byteArray the array that contains the TLV data object
* @param minOffset the first offset of the range to contain the TLV data object (inclusive)
* @param maxOffset the first offset of the range to not contain the TLV data object (exclusive).
* This offset may no longer be part of the array.
*/
public PrimitiveTlvDataObject(byte[] byteArray, int minOffset, int maxOffset) {
super(byteArray, minOffset, maxOffset);
if(!tlvTag.indicatesEncodingPrimitive()) {throw new IllegalArgumentException("tag must be primitive");}
int currentOffset = minOffset + tlvTag.getLength() + tlvLength.getLength();
tlvValuePlain = new TlvValuePlain(byteArray, currentOffset, currentOffset + tlvLength.getIndicatedLength());
}
/**
* Constructor for a TLV data object with primitive encoding based on an array of raw bytes.
*
* @param byteArray the array that contains the TLV data object
*/
public PrimitiveTlvDataObject(byte[] byteArray) {
this(byteArray, 0, byteArray.length);
}
/**
* Constructs an object from pre-fabricated elements explicitly setting a length field.
* Length fields only need to be explicitly set if their encoding complies with BER but
* not DER encoding rules or their encoding is intentionally damaged.
* @param tlvTagInput the tag to be used
* @param tlvLengthInput the length to be used (may be null)
* @param tlvValuePlainInput the value to be used
* @param performValidityChecksInput true: perform validity checks, false: do not perform validity checks
*/
public PrimitiveTlvDataObject(TlvTag tlvTagInput, TlvLength tlvLengthInput, TlvValuePlain tlvValuePlainInput, boolean performValidityChecksInput) {
super(performValidityChecksInput);
this.setTag(tlvTagInput, performValidityChecksInput);
this.setValue(tlvValuePlainInput);
if(tlvLengthInput != null) {
/* length must be set last as its validity check depends on the value already being set */
this.setLength(tlvLengthInput, performValidityChecksInput);
}
}
/**
* Constructs an object from pre-fabricated elements explicitly setting a length field.
* Length fields only need to be explicitly set if their encoding complies with BER but
* not DER encoding rules or their encoding is intentionally damaged.
* @param tlvTagInput the tag to be used
* @param tlvLengthInput the length to be used
* @param tlvValuePlainInput the value to be used
*/
public PrimitiveTlvDataObject(TlvTag tlvTagInput, TlvLength tlvLengthInput, TlvValuePlain tlvValuePlainInput) {
this(tlvTagInput, tlvLengthInput, tlvValuePlainInput, PERFORM_VALIDITY_CHECKS);
}
/**
* Constructs an object from pre-fabricated elements. Length field is implicitly set
* according to DER encoding rules by default.
* @param tlvTagInput the tag to be used
* @param tlvValuePlainInput the value to be used
* @param performValidityChecksInput true: perform validity checks, false: do not perform validity checks
*/
public PrimitiveTlvDataObject(TlvTag tlvTagInput, TlvValuePlain tlvValuePlainInput, boolean performValidityChecksInput) {
this(tlvTagInput, null, tlvValuePlainInput, performValidityChecksInput);
}
/**
* Constructs an object from pre-fabricated elements. Length field is implicitly set
* according to DER encoding rules by default.
* @param tlvTagInput the tag to be used
* @param tlvValuePlainInput the value to be used
*/
public PrimitiveTlvDataObject(TlvTag tlvTagInput, TlvValuePlain tlvValuePlainInput) {
this(tlvTagInput, tlvValuePlainInput, PERFORM_VALIDITY_CHECKS);
}
/**
* Constructs an object from a pre-fabricated tag and a provided array of raw value bytes
* @param tlvTagInput the tag to be used
* @param tlvValuePlainInput the raw value bytes to be used
*/
public PrimitiveTlvDataObject(TlvTag tlvTagInput, byte[] tlvValuePlainInput) {
this(tlvTagInput, new TlvValuePlain(tlvValuePlainInput));
}
/**
* Creates an empty object containing only a tag and length of zero.
* @param tlvTagInput the tag to be used
*/
public PrimitiveTlvDataObject(TlvTag tlvTagInput) {
this(tlvTagInput, new TlvValuePlain());
}
/*--------------------------------------------------------------------------------*/
@Override
public void setTag(TlvTag tlvTagInput, boolean performValidityChecksInput) {
if(tlvTagInput == null) {throw new NullPointerException("tag must not be null");}
if(!tlvTagInput.indicatesEncodingPrimitive()) {throw new IllegalArgumentException("tag must be primitive");}
performValidityChecks = performValidityChecksInput;
if(performValidityChecks) {
if(!tlvTagInput.isValidBerEncoding()) {throw new IllegalArgumentException("tag must be valid BER encoding");};
}
/*
* TLV tag must be cloned to eliminate outside access to this object.
* The tag must only be set by methods offered by this class e.g. to
* prevent setting the primitive tag to be a constructed tag.
*/
tlvTag = tlvTagInput.clone();
}
@Override
public byte[] getValueField() {
return tlvValuePlain.toByteArray();
}
@Override
public int getNoOfValueBytes() {
return tlvValuePlain.getLength();
}
/**
* Sets the value field of this object.
* Method does not override a super class method due to different signatures required for this method
* in both subclasses for primitive and constructed encoding.
* @param tlvValuePlainInput the value to be set
*/
public void setValue(byte[] tlvValuePlainInput) {
setValue(new TlvValuePlain(tlvValuePlainInput));
}
/**
* Sets the value field of this object.
* Method does not override a super class method due to different signatures required for this method
* in both subclasses for primitive and constructed encoding.
* @param tlvValuePlainInput the value to be set
*/
public void setValue(TlvValuePlain tlvValuePlainInput) {
if(tlvValuePlainInput == null) {throw new NullPointerException("value must not be null");}
tlvValuePlain = tlvValuePlainInput;
}
@Override
public TlvValuePlain getTlvValue() {
return tlvValuePlain;
}
@Override
public boolean isValidBerEncoding() {
if(!super.isValidBerEncoding()) {return false;}
return tlvTag.indicatesEncodingPrimitive();
}
}