VERFAHREN ZUM UMWANDELN VON AUSGANGSDATEN IN ZIELDATEN GEMÄß
ASN.1
Die vorliegende Erfindung betrifft die Umwandlung von Ausgangsdaten in Zieldaten gemäß ASN.1 . Insbesondere betrifft die Anmeldung ein ASN1 -Annotation-Framework zur
Umsetzung von Rechner-internen Datenstrukturen und Elementen in ein netzeinheitliches Format.
Die Abstract Syntax Notation One (ASN.1 ) ist eine Beschreibungssprache zur Definition von Datenstrukturen sowie Festlegungen zur Umsetzung von Datenstrukturen und Elementen in ein netzeinheitliches Format. ASN.1 ist gemeinsamer Standard der ITU-T (International Telecommunication Union - Telecommunication Standardization Sector) und der ISO (Internationale Organisation für Normung).
Der ASN.1 -Standard dient der abstrakten Beschreibung von Datentypen, ohne jedoch auf die rechnerinterne Darstellung von Datentypen einzugehen. Die Notation ist in den ITU-T- Standards X.680ff definiert. Die zugehörigen Standards X.690ff definieren verschiedene Kodierungsregeln, welche angeben, wie die ASN.1 -Datenwerte auf Bit-Ebene kodiert werden. Mit Hilfe von ASN.1 und einer gemeinsamen Encoding Rule können Systeme mit unterschiedlichen internen Datendarstellungen Nachrichten austauschen.
Es ist die Aufgabe der vorliegenden Erfindung, ein effizientes Konzept zur Umsetzung von Daten in ein netzeinheitliches Format gemäß ANS.1 zu schaffen.
Diese Aufgabe wird durch die Merkmale der unabhängigen Ansprüche gelöst. Vorteilhafte Ausführungsformen sind Gegenstand der abhängigen Ansprüche, der Beschreibung sowie der Zeichnungen.
Gemäß einem ersten Aspekt wird die erfindungsgemäße Aufgabe durch ein Verfahren zum Umwandeln von Ausgangsdaten in Zieldaten gemäß ASN.1 gelöst, mit den Schritten eines Einlesens zumindest einer digitalen Umwandlungsanweisung zum Umwandeln der
Ausgangsdaten in einem ersten Datenformat in die Zieldaten in einem zweiten Datenformat und eines Erzeugens der Zieldaten aus den Ausgangsdaten gemäß der
Umwandlungsanweisung. Dadurch kann eine ASN.1 Umwandlung automatisch und recheneffizient erstellt werden.
Das Verfahren wird gemäß einer Ausführungsform automatisiert mittels einer Datenverarbeitungsanlage, insbesondere mittels eines oder mehrerer Prozessoren ausgeführt. Die Ausgangsdaten, die Zieldaten sowie die zumindest eine oder mehrere Umwandlungsanweisungen sind digitalisiert und werden beispielsweise durch elektronische Signale oder Zustände von elektronischen Bauteilen repräsentiert. In dem Schritt des Einlesens werden gemäß einer Ausführungsform digitale Daten, welche die
Umwandlungsanweisung repräsentieren, automatisch eingelesen. Die zumindest eine Umwandlungsanweisung stellt gemäß einer Ausführungsform daher eine Anweisung an eine digitale Datenverarbeitungsanlage dar, welche die Datenverarbeitungsanlage zum automatischen Umwandeln der Daten veranlasst. Das Umwandeln wird gemäß einer Ausführungsform automatisch durchgeführt. Hierzu kann automatisch entweder eine Umwandlungsroutine ausgeführt werden oder es kann ein hierzu eingerichteter
Verarbeitungsschaltkreis eingesetzt werden, welcher die Umwandlung vornimmt. Das Datenformat ist ein digitales Datenformat, das beispielsweise eine zeitliche Anordnung von digitalen Werten der Ausgangsdaten oder von Datumsbestandteilen der Ausgangsdaten festlegt.
In einer vorteilhaften Ausführungsform ist die Umwandlungsanweisung in einem Quellcode vorgesehen. Dadurch wird beispielsweise der technische Vorteil erreicht, dass bereits beim Kompilieren des Quellcodes die Umwandlungsregeln gewonnen werden können. Der Quellcode kann beispielsweise in digitaler Form, beispielsweise in der Gestalt von
Binärwerten, in elektronischen Bauelementen gespeichert sein und so digital einlesbar sein. Die elektronischen Bauteile werden beispielsweise durch Speicherchips, ROM- oder RAM- Speicher, gebildet.
In einer weiteren vorteilhaften Ausführungsform ist der Quellcode eine Klassendefinition. Dadurch wird beispielsweise der technische Vorteil erreicht, dass sich die
Umwandlungsanweisungen von einer objektorientierten Programmiersprache für jedes aus der Klasse abgeleitete Objekt verwenden lassen und sich der technische Aufwand für ein Kompilieren verringert. Die Klassendefinition ist in einem Speicher gespeichert und dient als ein abstraktes Modell oder ein Bauplan für eine Reihe von ähnlichen Objekten. Die
Klassendefinition kann beispielsweise in digitaler Form, beispielsweise in der Gestalt von Binärwerten, in elektronischen Bauelementen gespeichert sein und so digital einlesbar sein.
In einer weiteren vorteilhaften Ausführungsform umfasst das Verfahren den Schritt eines Parsens des Quellcodes zum Einlesen der Umwandlungsanweisung. Durch den technischen
Prozess des Parsens wird beispielsweise der technische Vorteil erreicht, dass sich die Umwandlungsanweisungen einfach durch systematisches Analysieren von Quellcodes ermitteln und extrahieren lassen, die in elektronischen Bauteilen gespeichert sind. Der Parser kann als eine separate Schaltung oder als eine Programmkomponente gebildet sein, die den digital gespeicherten Quellcode grammatikalisch und/oder syntaktisch analysiert.
In einer weiteren vorteilhaften Ausführungsform umfasst das Verfahren den Schritt eines Aufrufens eines Umwandlers zum Einlesen der Umwandlungsanweisung und Erzeugen der Zieldaten. Dadurch wird beispielsweise der technische Vorteil erreicht, dass die Umwandlung von einer getrennten Instanz durchgeführt wird und sich eine Stabilität und Zuverlässigkeit des Verfahrens auf einer Datenverarbeitungsanlage verbessert. Der Umwandler kann beispielsweise durch einen separaten Prozessor oder eine integrierte Schaltung auf einem Schaltungsbrett gebildet sein, der die digitalen Umwandlungssignale verarbeitet. In einer anderen Ausführungsform ist der Umwandler durch eine Routine oder ein Programm gebildet, das auf einer Datenverarbeitungsanlage läuft.
In einer weiteren vorteilhaften Ausführungsform umfasst das Verfahren den Schritt eines Steuerns des Umwandlers über die Umwandlungsanweisung. Dadurch wird beispielsweise der technische Vorteil erreicht, dass sich die technischen Einsatz- und
Konfigurationsmöglichkeiten des Umwandlers erhöhen. Insbesondere können Signale zum Steuern des Umwandlers in technisch besonders einfacher Weise übertragen werden.
In einer weiteren vorteilhaften Ausführungsform umfasst das Verfahren den Schritt eines Aufrufens des Umwandlers über ein Objekt. Dadurch wird beispielsweise der technische Vorteil erreicht, dass der Umwandler in technisch einfacher Weise in einer objektorientierten Programmiersprache direkt aus einem Objekt heraus aufgerufen und gestartet werden kann und sich eine Komplexität eines Aufrufs verringert. Das Objekt ist ein Datenspeicherbereich in einer Ausführungsumgebung, dessen Inhalte Werte darstellen können. Jedes Objekt hat einen Zustand, ein Verhalten und eine Identität. Das Objekt ist in binärer Form in
elektronischen Bauelementen gespeichert. Der Zustand des Objektes setzt sich aus seinen Eigenschaften (Attribute) und Verbindungen zu anderen Objekten zusammen. Das Verhalten des Objektes wird durch die Menge seiner Methoden beschrieben. Die Identität
unterscheidet ein Objekt von anderen Objekten, auch wenn diese anderen Objekte den gleichen Zustand und das gleiche Verhalten haben.
In einer weiteren vorteilhaften Ausführungsform umfasst das Verfahren den Schritt eines Auslesens der Umwandlungsanweisung aus einer Klassendefinition des aufrufenden Objektes. Dadurch wird beispielsweise der technische Vorteil erreicht, dass die
Umwandlungsdaten auf einfache technische Weise bei einem Aufrufen des Objektes aus der Klassendefinition gewonnen werden können und sich ein benötigter Speicherplatz für die Umwandlungsanweisungen verringert.
In einer weiteren vorteilhaften Ausführungsform umfasst das Verfahren den Schritt eines Erzeugens der Zieldaten aus Objektdaten. Dadurch wird beispielsweise der technische Vorteil erreicht, dass die Zieldaten über den Austausch von digitalen Signalen automatisch erzeugt werden können. Die Objektdaten sind in einem elektronischen Bauteil gespeicherte Daten, die das Objekt darstellen.
In einer weiteren vorteilhaften Ausführungsform umfasst das Verfahren den Schritt eines Zurückgebens der Zieldaten über das aufrufende Objekt. Dadurch wird beispielsweise der technische Vorteil erreicht, dass die Zieldaten nach der Rückgabe weiter verarbeitet werden können und sich die Anzahl von Speicherzugriffen vermindert.
In einer weiteren vorteilhaften Ausführungsform formen die Zieldaten eine ASN.1 -Sequenz. Dadurch wird beispielsweise der technische Vorteilerreicht, dass die Zieldaten mit einer geringen Anzahl von Signalen direkt an ein Netzwerk ausgegeben werden können.
In einer weiteren vorteilhaften Ausführungsform wird die ASN.1 -Sequenz über ein
Datennetzwerk übertragen. Dadurch wird beispielsweise der technische Vorteil erreicht, dass die ASN.1 -Signale in einer Netzwerkschicht zu anderen Datenverarbeitungsanlagen übertragen werden können.
In einer weiteren vorteilhaften Ausführungsform umfasst das Verfahren den Schritt eines Abbildens je einer Umwandlungsanweisung auf je einen Datentyp der Ausgangsdaten.
Dadurch wird beispielsweise der technische Vorteil erreicht, dass sich für jeden Datentyp eine entsprechende Umwandlung durchführen lässt und sich der Aufwand zum Analysieren der digitalen Umwandlungsanweisungen vermindert. Der Datentyp stellt gemäß einer Ausführungsform eine Zusammenfassung konkreter Wertebereiche und darauf definierten Operationen zu einer Einheit dar und definiert das Speicherformat der Wertebereiche in elektronischen Bauteilen.
Gemäß einem zweiten Aspekt wird die erfindungsgemäße Aufgabe durch einen Umwandler zum Umwandeln von Ausgangsdaten in Zieldaten gemäß ASN.1 gelöst, mit einer
Einlesevorrichtung zum Einlesen zumindest einer digitalen Umwandlungsanweisung zum Umwandeln der Ausgangsdaten in einem ersten Datenformat in die Zieldaten in einem zweiten Datenformat; und einer Erzeugungsvorrichtung zum Erzeugen der Zieldaten aus den Ausgangsdaten gemäß der Umwandlungsanweisung. Dadurch werden die gleichen technischen Vorteile wie durch das Verfahren nach dem ersten Aspekt erreicht. Der
Umwandler kann in Software und/oder in Hardware realisiert werden.
Gemäß einem dritten Aspekt wird die erfindungsgemäße Aufgabe durch ein
Computerprogrammprodukt gelöst, das direkt in den internen Speicher eines digitalen Computers geladen werden kann und Softwarecodeabschnitte umfasst, mit denen das Verfahren nach dem ersten Aspekt ausgeführt wird, wenn das Produkt auf einem Computer läuft. Dadurch werden die gleichen technischen Vorteile wie durch das Verfahren nach dem ersten Aspekt erreicht.
Weitere Ausführungsbeispiele werden in Bezug auf die Zeichnungen beschrieben Es zeigen: Fig. 1 eine schematische Darstellung einzelner Verfahrensschritte; Fig. 2 eine schematische Ansicht eines Frameworks; Fig. 3 ein Ablaufdiagramm eines einfachen Flusses; Fig. 4 ein Ablaufdiagramm eines komplexen Flusses;
Fig. 5 ein Blockdiagramm einer Reihenfolge der Aktionen beim Erstellen und Parsen;
Fig. 6 eine Tabelle mit Java-Basistypen und ASN1 -Basistypen;
Fig. 7 eine Tabelle mit Deklarationsmöglichkeiten für ein Feld; und
Fig. 8 eine Tabelle mit in der ASN1 -Sprache existierenden Constraint-Annotationen.
Fig. 1 veranschaulicht die Funktionsweise des ASN1 -Framework-Verfahrens gemäß einer Ausführungsform. Auf dem selbst erstellten ASN1 -Objekt, das mit zusätzlichen
Anmerkungen 103 versehen wird, kann direkt durch einen entsprechenden Funktionsaufruf 107 getDERObject der Umwandlungsprozess der Ausgangsdaten 100 in die Zieldaten 101 gestartet werden. Die in dem ASN1 -Objekt bereitgestellten Anmerkungen 103 werden im Folgenden als Annotationen oder Annotations bezeichnet.
Bei der Umwandlung wird das Objekt in Schritt S101 des Konvertierens selbst zur
Konvertierung verwendet und an interne Handler des ASN1 -Frameworks 105 weitergeleitet, das als eine Umwandlungseinrichtung dient. Durch das ASN1 -Framework 105 werden in Schritt S102 des Einlesens die Annotationen 103 des Objektes ermittelt, die als
Umwandlungsanweisung zum Umwandeln von Daten in ein netzeinheitliches Format dienen. Sollten sich weitere komplexe Objekte in einem Baum befinden, so wird auch hier eine Ermittlung der Annotationen 103 vorgenommen. Anschließend sorgt das ASN1 -Framework 105 in Schritt S103 des Interpretierens dafür, dass die ASN1 -Struktur mit Hilfe eines darunter liegenden ASN1 -Konverters, wie beispielsweise Bouncycastle erstellt wird. Diese Struktur wird in Schritt S104 der Rückgabe nun an den logischen Code, d.h. den Aufrufer,
zurückgegeben, der sich in Schritt S105 (Ergebnis) anschließend daraus die ASNI -Bytes abholen kann.
Im nachfolgenden Teil werden die technischen Funktionsweisen des ASN1 -Frameworks 105 und dessen Annotationen 103 in Zusammenhang mit der objektorientierten
Programmiersprache JAVA näher erläutert.
Bei der Verarbeitung wird zunächst das Objekt analysiert. Dabei werden sämtliche
Annotationen eingelesen, die an diesem Objekt hängen. Diese Gesamtheit wird durch ASN1 ClassDefinition beschrieben, die im nachfolgenden Code-Fragment erzeugt wird:
Map<MapType, Object> map = findASNI TypeAnnotation(clazz);
Annotation asnITypeAnnotation = (Annotation) map.get(MapType.ASNI );
List<ASN1 Constraints> asnI Constraints = (List<ASN1 Constraints>)
map.get(MapType.ConstraintList);
//Add all constraints annotations
ASN1 ClassDefinition asnl ClassDefinition = new
ASN1 ClassDefinition(asn1 TypeAnnotation, asnl Constraints, clazz);
Dieses Code-Fragment beinhaltet jedoch nicht die vollständige Logik.
Darüber hinaus wird für jede Klasse eine Liste von ASN1 FieldDefinition angelegt.
ASN1 FieldDefinition beinhaltet, ähnlich wie die ASN1 ClassDefinition die Gesamtheit aus dem Feld und den Annotationen an diesem Feld. Das nachfolgende Code-Fragment zeigt die logische Verarbeitung:
//Use only fields (or its getter methods***) which annotated with a ASNUype Annotation asnUypeAnnotation = null;
for (Annotation annotation : field.getAnnotations()) {
if (annotation. annotationType().getAnnotation(ASN1Type.class) != null) { asnUypeAnnotation = annotation;
break;
}
}
//*** If not found a field with an ASNUype annotation and the read method exists //check this method annotations
if (asnUypeAnnotation == null && readMethod != null) {
for (Annotation annotation : read Method. getAnnotations()) {
if (annotation. annotationType().getAnnotation(ASN1 Type.class) != null) { asnUypeAnnotation = annotation;
break;
}
}
}
//Continue if this field is not annotated with a asnl type annotation
if (asnUypeAnnotation == null) {
return null;
}
//Get the base ASN1 Annotation and all its Information
ASNUag tag = field.getAnnotation(ASNUag.class);
if (tag == null && readMethod != null) { //Only if the tag was not found on field tag = readMethod. getAnnotation(ASNUag.class);
}
ASN1 Information Information =
asnUypeAnnotation.annotationType().getAnnotation(ASN1 Information. class);
Method readMethod_ = null;
Method writeMethod = null;
ASN1 FieldDefinition asnI FieldDefinition = new
ASN1 FieldDefinition(asn1 TypeAnnotation, field, clazz, readMethod_, writeMethod);
Dieses Code-Fragment beinhaltet jedoch ebenfalls nicht die vollständige Logik. Um eine korrekte ASN1 -Annotation zu ermitteln, wird überprüft, ob diese selbst mittels der
ASNIType- und ASN1lnformation-Annotat\on mit Annotationen versehen worden ist. Ein Beispiel für eine typische ASN1 Type-Annotation ist:
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType. FIELD, ElementType.TYPE, ElementType. METHOD}) @ASN1 lnformation(complex = false, asnI CIass = {DERInteger.class,
DEROctetString.class}, tagNumber = ASNI Object. INTEGER) //Additional ASN1 - Information, must be set
@ASN1 Type //Make it to a ASN1 -Type-Annotation
public @interface ASN1 Integer {
* Mark integer as unsigned
*
* @ return
7
boolean unsigned() default false;
ASNI SingleValueConstraint singleValueConstraint() default
@ASN1 SingleValueConstraint("");
ASNIValueRangeConstraint valueRangeConstraint() default
@ASN1ValueRangeConstraint();
}
Der Vorteil des ASN1 -Frameworks liegt in der Geschwindigkeit der Implementierung. So können beispielsweise bis zu 80% der Zeit eingespart werden. Im folgenden Teil wird ein Vergleich zwischen der herkömmlichen Verwendung und der Verwendung des ASN1 - Frameworks gezeigt:
Dazu wird das ASN1 -Skript vorgegeben:
Object ::= SEQUENCE {
valuel [10] INTEGER(0..100),
value2 [1 1] UTF8String OPTIONAL
}
Ohne die Verwendung des Frameworks ergibt sich der Code des ASN1 -Objektes: public class DEROId implements DEREncodable {
public static DEROId getlnstance(byte[] buffer) throws lOException { int value;
String str = null;
DERTaggedObject tag = null;
ASNI Object obj = ASNI Object.fromByteArray(buffer);
if (!(obj instanceof DERSEQUENCE))
throw new RuntimeException("Wrong type!");
DERSEQUENCE SEQUENCE = (DERSEQUENCE) obj;
if (SEQUENCE.size() < 1 )
throw new RuntimeException("Wrong size of SEQUENCE!");
if (!(SEQUENCE.getObjectAt(0) instanceof DERTaggedObject)) throw new RuntimeException("Wrong type!");
tag = (DERTaggedObject) SEQUENCE.getObjectAt(O);
if (tag.getNumber() != 10)
throw new RuntimeException("Wrong tag number!");
if (!(tag.getObject() instanceof DERInteger))
throw new RuntimeException("Wrong type!");
value = ((DERInteger) tag.getObject()).getPositiveValue().intValue(); //optional
if (SEQUENCE.size() > 1 ) {
if (!(SEQUENCE.getObjectAt(1 ) instanceof DERTaggedObject)) throw new RuntimeException("Wrong type!");
tag = (DERTaggedObject) SEQUENCE.getObjectAt(l );
if (tag.getNumber() != 1 1 )
throw new RuntimeException("Wrong tag number!");
if (!(tag.getObject() instanceof DERUTF8String))
throw new RuntimeException("Wrong type!");
str = ((DERUTF8String) SEQUENCE.getObjectAt(1 )).getString();
}
DEROId old = new DEROId(value, str);
validate(old);
return old;
}
//Validation
private static void validate(DEROId obj) {
if (obj.getValue1 () < 0 || obj.getValue1 () > 100)
throw new RuntimeException("Out of ränge!");
}
private int valuel ;
private String value2;
public DEROId() {
}
public DEROId(int valuel , String value2) {
this. valuel = valuel ;
this.value2 = value2;
}
public int getValue1 () {
return valuel ;
}
public void setValue1 (int valuel ) {
this. valuel = valuel ;
}
public String getValue2() {
return value2;
}
public void setValue2(String value2) {
this.value2 = value2;
}
public DERObject getDERObject() {
validate(this);
ASN1 EncodableVector vec = new ASN1 EncodableVectorQ;
DERInteger intValue = new DERInteger(valuel );
DERTaggedObject tag10 = new DERTaggedObject(10, intValue);
vec.add(tagl O);
if (value2 != null) {
DERUTF8String strValue = new DERUTF8String(value2);
DERTaggedObject tagl 1 = new DERTaggedObject(1 1 , strValue);
vec.add(tag1 1 );
}
return new DERSEQUENCE(vec);
}
}
Das Erstellen des Objekts erfolgt über:
DEROId obj = new DEROId(10, "Hallo");
byteQ buffer = obj.getDERObject().getDEREncodable();
Das Parsen erfolgt über:
DEROId obj = DEROId.getlnstance(buffer);
Mit Verwendung des erfindungsgemäßen Frameworks ergibt sich der Code des ASN1 - Objektes:
@ASN1 SEQUENCE
public class DERNew extends DERRoot {
@ASN1 SEQUENCEField(position = 1 )
@ASN1 lnteger(
valueRangeConstraint = @ASN 1ValueRangeConstraint(minimum = 0, maximum = 100)
)
@ASN1Tag(number = 10, type = ASNI TagType.CONSTRUCTED)
private int valuel ;
@ASN1 SEQUENCEField(position = 2, optional = ASNI Optional.NotNull)
@ASN1 UTF8String
@ASN1Tag(number = 1 1 , type = ASNI TagType.CONSTRUCTED)
private int value2;
public DERNew() {
}
public DERNew(int valuel , int value2) {
this.valuel = valuel ;
this.value2 = value2;
}
public int getValue1 () {
return valuel ;
}
public void setValue1 (int valuel ) {
this.valuel = valuel ;
}
public int getValue2() {
return value2;
}
public void setValue2(int value2) {
this.value2 = value2;
}
}
Das Erstellen des Objekts erfolgt über:
DEROId obj = new DEROId(10, "Hallo");
byteQ buffer = obj.getDERObject().getDEREncodable();
Das Parsen erfolgt über:
DEROId obj = DERRoot.getlnstance(buffer, DEROId.class);
Der größte Aufwand - die Implementierung des Erstellens und des Parsens - entfällt im Vergleich zu dem erstgenannten Beispiel. Das Verfahren kann mit weniger Rechenschritten und in geringerer Zeit durchgeführt werden. Dabei bleiben die Aufrufe, die im Code anzugeben sind, im Wesentlichen gleich.
Jede Klasse, die als eigenständiges ASN1 -Objekt verwendet werden soll, erbt von der Klasse DERRoot. In dieser Klasse befindet sich die gesamte Code-Logik, um das Parsen und Erstellen der ASN1 -Byte-Arrays über die Annotationen auszuführen. Jede Klasse weist zu diesem Zweck einen ASN1 -Typen auf, unabhängig davon, ob dieser von einem einfachen Typ (Integer, Boolean, ...) oder von einem komplexen Typ komplex (SEQUENCE, SET) ist.
Jedes Feld, das zur Erstellung des Byte-Codes verwendet werden soll, weist ebenfalls einen einfachen ASN1 -Typ als Annotation auf.
Fig. 2 gibt einen ersten Überblick über den Aufbau des ASN1 -Frameworks 200, in dem vereinfacht lediglich die Handler für die einfachen ASN1 -Typen dargestellt sind.
Als Basis des ASN1 -Frameworks 200 dient das Objekt DERRoot. Dieses Objekt besitzt die vererbte Methode createDERObject aus dem Bouncycastle-Framework sowie die statische Methode getlnstance, die das Parsen realisiert. Für die auf beiden Seiten dargestellten Bereiche Parsing und Creation, existiert jeweils ein Root-Handler 201 und 203, der wiederum die Utility und diverse Objekt-Handler anspricht.
Fig. 3 zeigt ein Diagramm eines Verfahrens zur vereinfachten ASN.1 -Erzeugung 301 (ASN.1 Simple Creation) unter Verwendung der Entitäten Creation Root Handler 303, Creation Utility 305 und Integer Handler 307 dargestellt. Im Schritt 309 wird die Routine create DERObject() ausgeführt, mit dem Übergang mit create DERObject(this) in den Schritt 31 1. Von dem Schritt 31 1 aus findet ein Übergang in den Schritt 313 mit handleClassAnnotation(Object): DERObject statt, in welchem convert(Object): DERObject ausgeführt wird.
Fig. 4 zeigt ein Diagramm eines Verfahrens zur komplexen ASN.1 -Erzeugung 301 (ASN.1 Complex Creation) 401 , mit der weiteren Entität Sequence Handler 403. Im Schritt 405 wird die Routine create DERObject() ausgeführt, mit dem Übergang mit create DERObject(this) in den Schritt 407. Von dem Schritt 407 aus findet ein Übergang in den Schritt 407 mit handleClassAnnotation(Object): DERObject in den Schritt 413 statt. Von dem Schritt 413 aus findet ein Übergang in den Schritt 409 mit getFields) : List<Fields> statt. Hiernach kann von dem Schritt 409 optional in den Schritt 413 übergangen werden. Hiernach können die Routinen checkFields() und sortFields() ausgeführt werden, wonach ein Übergang in den Schritt 41 1 mit generateVector(fields): Vector erfogen kann. Danach kann mit
handleFieldAnnotation(DERObject) ein Übergang in den Schritt 414 stattfinden. Von dem Schritt 414 aus kann ein Übergang in den Schritt 41 1 und von dort aus in den Schritt 413
erfolgen. Hiernach kann im Schritt 413 die Routine createDERObject(Vector): DERObject ausgeführt werden. Hiernach kann ein Übergang in den Schritt 407 erfolgen.
Fig. 5 zeigt ein Diagramm eines Verfahrens 501 gemäß einer Ausführungsform, in dem verdeutlicht wird, in welcher Reihenfolge die Aktionen beim Erstellen und Parsen ausgeführt werden.
Beginnend mit„Start" wird der Schritt 503,„ Finde ASN1 -Type-Annotation auf Klasse" ausgeführt. Danach wird entschieden, ob Creation/Parsing (Handlingkomplex) ausgeführt werden sollen. In Abhängigkeit von der Entscheidung wird der Schritt 507,„Handle einfachen Typ" oder 509,„Handle Sequences/Sets", ausgeführt. Von dem Schritt 507 aus findet die Terminierung in dem Schritt 527 statt.
Nach dem Schritt 509 wird der Schritt 51 1 ,„Finde alle Felder mit ASN1 -Typ-Annotation" ausgeführt. Danach wird im Schritt 513 entschieden, ob mit dem Schritt 525 weiter verfahren werden soll, oder ob einer der Schritte 517, 519 oder 521 ausgeführt werden soll. Die komplexe Abarbeitung wird im Schritt 519,„Creation/Parsing (Handling komplex)" durchgeführt. Im Schritt 519 wird die optionale Routine„Handle Sequence" ausgeführt. Im Schritt 521 wird die Routine„Handle einfachen Typ" ausgeführt. Von den Schritten 517, 519 und 521 aus findet jeweils ein Übergang in den Schritt 523 statt, von wo aus ein Übergang in den Schritt 525 stattfinden kann. Von dem Schritt 525 aus findet die Terminierung in dem Schritt 529,„Ende", statt.
Das Erstellen eines Byte-Arrays von einem ASN1 -Annotation-Framework-Objekts wird durch folgenden Code erreicht: public class MyObject extends DERRoot {
public static void main(String[] args) {
MyObject obj = new MyObject();
obj.setValue(100);
DEREncodable derObj = obj.getDERObject();
byte[] array = derObj.getDEREncoded();
}
}
Durch den Aufruf der Methode getDERObject wird der Vorgang eines Erstellens gestartet. Nach dem Aufruf wird ein Bouncycastle-Encodable erhalten, das nur noch aus Basis- Objekten besteht.
Das Parsen eines Byte-Arrays ist ebenfalls einfach: byteQ buffer = new HexBinaryAdapter().unmarshal("020100");
MyObject obj = DERRoot.getlnstance(buffer, MyObject.class);
Durch diese zwei Zeilen wird der Parsing-Algorithmus in DERRoot angestoßen.
Anschließend wird das komplett zusammengesetzte Objekt erhalten.
Fig. 6 zeigt einfache und komplexe Typen des ASN1 -Frameworks. Bei einfachen Typen handelt es sich in erster Linie um Basis-Typen der ASN1 -Spezifikationen, wie beispielsweise Integer, Boolean oder Octet-String. Diese einfachen Datentypen können auf verschiedenen Java-Basistypen abgebildet werden, d.h. gemappt, werden. Die in Fig. 6 dargestellte Tabelle zeigt, welche Java-Basistypen für welche ASN1 -Basis-Typen verwendet werden können.
Darüber hinaus können alle Felder den ASN1 -Basis-Typ aus dem Bouncycastle-Framework verwenden. Alle aufgeführten ASN1 -Typen, mit Ausnahme von null, der nur bei Klassen angewendet wird, können diese Typen sowohl auf Felder als auch auf Klassen gemappt werden.
Es gibt für jeden der oben aufgeführten Basis-Typen mit Ausnahme von null eine
Möglichkeit, eine Enumeration festzulegen, die eine Get- und eine Find- Methode besitzt. Der Typ, der für einen Enumeration-Wert verwendet wird, sollte mit den oben aufgeführten unterstützen Typen übereinstimmen.
Im folgenden Code als Klassenbeispiel wird eine Variable von Typ Integer definiert. Diese Deklaration verhält sich analog zur ASN1 -Deklaration:
MyObject ::= INTEGER
@ASN1 Integer
public class MyObject extends DERRoot {
@ASN1TargetField
private Biginteger value;
public MyObject() {
super();
}
public MyObject(Biglnteger value) {
this. value = value;
}
public Biginteger getValue() {
return value;
}
public void setValue(Biglnteger value) {
this. value = value;
}
}
Hier wird die Klasse als ASNIInteger markiert. Das Feld value dient dabei als ein Zielfeld für den tatsächlichen Wert, der aus dem ASN1 -Byte-Array extrahiert wird oder zum Erstellen des ASN1 -Byte-Arrays verwendet werden soll. Alternativ könnte sich diese Annotation auch an einer Get-Methode des Feldes befinden:
@ASN1 Integer
public class MyObject extends DERRoot {
private Biginteger value;
public MyObject() {
super();
}
public MyObject(Biglnteger value) {
this. value = value;
}
@ASN1TargetField
public Biginteger getValue() {
return value;
}
public void setValue(Biglnteger value) {
this. value = value;
}
}
Für einen Wert von 100 wird dabei folgender ASN1 -Byte-Code erstellt: 020164
In diesem Beispiel wird der ASN1 -Basis-Typ an ein Feld angeheftet. Die Klasse selbst repräsentiert dabei eine Sequenz (SEQUENCE), die nur aus einem einzigen Feld besteht, nämlich einem ASNIInteger.
MyObject ::= SEQUENCE {
value INTEGER
}
@ASN1 SEQUENCE
public class MyObject extends DERRoot {
@ASN1 Integer
@ASN1 SEQUENCEField(position = 1 )
private int value;
public int getValue() {
return value;
}
public void setValue(int value) {
this. value = value;
}
}
Die Bedeutung von ASN1 SEQUENCEField wird später erläutert. Das Feld value ist als ASNIInteger markiert. Alternativ wäre auch hier folgende Annotation möglich:
@ASN1 SEQUENCE
public class MyObject extends DERRoot {
@ASN1 SEQUENCEField(position = 1 )
private int value;
©ASNI Integer
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
Bei diesem Beispiel entsteht mit dem Wert 100 folgendes ASN-Byte-Array: 3003020164.
Zusätzlich zu den ASN1 -Basis-Typen gibt es komplexe Typen und Objekte, um komplexere Strukturen darzustellen. Neben den Typen SEQUENCE (Sequenz) und SET (Menge) gibt es im ASN1 -Annotation-Framework auch eine Annotation für CHOICE (Wahl). Dabei können auch komplexe Unterobjekte in diese Strukturen aufgenommen werden.
SEQUENCE ist vergleichbar mit SET mit dem Unterschied, dass bei SEQUENCE die Reihenfolge frei wählbar ist, während diese bei SET durch die ASN1 -Spezifikation vorgeschrieben wird. Beispielsweise ist SEQUENCE gegeben durch:
MyObject ::= SEQUENCE {
valuel INTEGER,
value2 UTF8String
value3 INTEGER OPTIONAL
}
@ASN1 SEQUENCE
public class MyObject extends DERRoot {
@ASN1 Integer
@ASN1 SEQUENCEField(position = 1 )
private Integer valuel ;
//Type set on getter
@ASN1 SEQUENCEField(position = 2)
private String value2;
@ASN1 Integer
@ASN1 SEQUENCEField(position = 3, optional = ASN I Optional.NotNull)
private Integer value3;
public Integer getValuel () {
return valuel ;
}
public void setValuel (Integer valuel ) {
this. valuel = valuel ;
}
@ASN1 UTF8String
public String getValue2() {
return value2;
}
public void setValue2(String value2) {
this.value2 = value2;
}
public Integer getValue3() {
return value3;
}
public void setValue3(lnteger value3) {
this.value3 = value3;
}
}
Die Klasse selbst wird hierbei mit einer ASN1 -SEQUENCE Annotation markiert. Jedes Feld, das Bestandteil von SEQUENCE werden soll, besitzt die Annotation ASN1 SEQUENCEField mit einer entsprechenden Position. Die Position ist eine beliebige Zahl, die innerhalb von SEQUENCE nicht doppelt vorkommt. Die Reihenfolge ergibt sich dann aus der Sortierung der Felder anhand dieser Positionsnummer. Darüber hinaus kann ein Feld auch als optional markiert werden. Dieses Feld kann auch null sein. Bei SET ist die Vorgehensweise analog:
MyObject ::= SET {
valuel INTEGER,
value2 UTF8String
value3 INTEGER OPTIONAL
}
@ASN1 SET
public class MyObject extends DERRoot {
@ASN1 Integer
@ASN1 SETField
private Integer valuel ;
//Type set on getter
@ASN1 SETField
private String value2;
@ASN1 Integer
@ASN1 SETField(optional = ASNI Optional.NotNull)
private Integer value3;
public Integer getValuel () {
return valuel ;
}
public void setValuel (Integer valuel ) {
this. valuel = valuel ;
}
@ASN1 UTF8String
public String getValue2() {
return value2;
}
public void setValue2(String value2) {
this.value2 = value2;
}
public Integer getValue3() {
return value3;
}
public void setValue3(lnteger value3) {
this.value3 = value3;
}
}
Auch hier sind alle Felder, die Bestandteil von SET werden sollen, mit der Annotation ASNISETField markiert. Im Gegensatz zu SEQUENCE können hier keine Positionen für einzelne Felder angegeben werden, da, wie oben bereits erwähnt, die Reihenfolge bei SET nicht festgelegt werden kann. Auch hier sind optionale Felder möglich.
Es gibt die Möglichkeit, auch verschiedene komplexere Typen in SEQUENCE und SET zu verwenden und dadurch eine Verschachtelung von SEQUENCE- und SET-Bereichen zu erhalten:
MyObjectA ::= SEQUENCE {
valuel INTEGER,
value2 UTF8String,
value3 INTEGER OPTIONAL
}
MyObjectB ::= SEQUENCE {
valuel INTEGER,
value2 MyObjectA
}
@ASN1 SEQUENCE
public class MyObjectA extends DERRoot {
@ASN1 Integer
@ASN1 SEQUENCEField(position = 1 )
private Integer valuel ;
//Type set on getter
@ASN1 SEQUENCEField(position = 2)
private String value2;
@ASN1 Integer
@ASN1 SEQUENCEField(position = 3, optional = ASN I Optional.NotNull) private Integer value3;
public Integer getValuel () {
return valuel ;
}
public void setValuel (Integer valuel ) {
this. valuel = valuel ;
}
@ASN1 UTF8String
public String getValue2() {
return value2;
}
public void setValue2(String value2) {
this.value2 = value2;
}
public Integer getValue3() {
return value3;
}
public void setValue3(lnteger value3) {
this.value3 = value3;
}
}
@ASN1 SEQUENCE
public class MyObjectB extends DERRoot {
@ASN1 Integer
@ASN1 SEQUENCEField(position = 1 )
private Integer valuel ;
@ASN1 Complex
@ASN1 SEQUENCEField(position = 2)
private MyObjectA value2;
public Integer getValuel () {
return valuel ;
}
public void setValuel (Integer valuel ) {
this. valuel = valuel ;
}
public MyObjectA getValue2() {
return value2;
}
public void setValue2(MyObjectA value2) {
this.value2 = value2;
}
}
Der Code demonstriert, wie ein komplexes Objekt in ein anderes komplexes Objekt einfügt wird. Value2 vom Typ MyObjectA wird dabei mit ASN1 Complex markiert und zeigt an, dass es sich hierbei um ein inneres komplexes Objekt handelt. Aus diesem Beispiel entstehen zwei ineinander verschachtelte S£QL/£/VC£-Bereiche. Natürlich kann auch für komplexe Felder das opi/ona/-Attribut verwendet werden. Die Vorgehensweise ist bei SET analog.
In bestimmten Fällen soll lediglich ein bestimmtes Objekt innerhalb von SEQUENCE oder S£7 auftreten. Zu diesem Zweck ist in der ASN1 -Syntax den OF-Operator für SEQUENCE und SET vorgesehen. Im folgenden Beispiel wird ASN1 SEQUENCEOf verwendet:
MyObject ::= SEQUENCE OF INTEGER
@ASN1 SEQUENCEOf
public class MyObjectB extends DERRoot {
@ASN1 Integer
@ASN1TargetField
private List<lnteger> value = new Arrayl_ist<lnteger>();
@Override
public void validate() {
}
public List<lnteger> getValue() {
return value;
}
}
Innerhalb von ASNISEQUENCEOf kann es nur eine Liste geben, die mit der Annotation ASNI TargetField markiert ist. Diese enthält dann immer wieder das gleiche Objekt, hier beispielsweise Integer. Allerdings können auch komplexe und abstrakte Objekte verwendet werden. Diese Vorgehensweise ist bei ASN1SETO† analog:
MyObject ::= SET OF INTEGER
@ASN1 SETOf
public class MyObjectB extends DERRoot {
@ASN1 Integer
@ASN1TargetField
private List<lnteger> value = new ArrayList<lnteger>();
public List<lnteger> getValue() {
return value;
}
}
CHOICE (Wahl) definiert, dass nur eines der aufgelisteten Felder verwendet werden darf. Die anderen Felder bleiben null. Das nachfolgende Beispiel beschreibt eine einfache CHOICE:
MyObject ::= CHOICE {
valuel INTEGER,
value2 UTF8String
}
@ASN1 Choice
public class MyObject extends DERRoot {
@ASN1 Integer
private Integer valuel ;
//Type set on getter
private String value2;
@Override
public void validate() {
}
public Integer getValuel () {
return valuel ;
}
public void setValuel (Integer valuel ) {
this. valuel = valuel ;
}
@ASN1 UTF8String
public String getValue2() {
return value2;
}
public void setValue2(String value2) {
this.value2 = value2;
}
}
Hier wird nur eines der Felder valuel oder value2 gesetzt. Das jeweils andere Feld wird auf null gesetzt, da andernfalls eine ASN1 -Exception ausgegeben wird. In analoger Weise verhält es sich, wenn kein Feld gesetzt ist. Auch in diesem Fall können komplexe Objekte verwendet werden, solange die Felder eindeutig bleiben.
Die Felder CHOICE (Wahl) sollten eindeutig sein. Werden komplexe Objekte verwendet, sollten diese ebenfalls in ihrer eigenen Struktur in Bezug auf CHOICE eindeutig sein.
Andernfalls wird beim Parsen eine ASN1 -Exception geworfen. Allerdings ist auch eine Verwendung von Tags möglich.
In ASN1 existieren zwei verschiedene Möglichkeiten, ein Feld als optional zu deklarieren: Entweder das Feld wird mit null (0500) aufgefüllt oder es wird einfach weggelassen. Wird es mit null gefüllt, so bleibt auch der möglicherweise definierte Tag erhalten. Wird es einfach nur weggelassen, verschwindet auch der Tag.
Fig. 7 zeigt die unterschiedlichen Möglichkeiten in Tabellenform.
Es gibt weitere Möglichkeiten, die Struktur der ASN1 -Bytes zu definieren. Darunter gehört in erster Linie das Verwenden von Tags, aber auch der Ausbau von noch komplexeren Feldern SEQUENCE und SET mittels des OF-Operators. Im nachfolgenden Teil wird auf diese ASN1 -Erweiterungen eingegangen.
In ASN1 existieren die Tag-Typen: Das CONSTRUCTED-Jag und das APPLICATION-Tag. Diese Tags können vor jedem Objekt angeordnet werden, um Eindeutigkeit zu erreichen. Diese Vorgehensweise ist bei SEQUENCE und SET von Vorteil, wenn diese mehrere optionale Felder des gleichen Typs besitzen.
In diesem Beispiel wird eine SEQUENCE erzeugt, dessen Felder mit einem
CONSTRUCTED-Jag versehen werden:
MyObject ::= SEQUENCE {
valuel [0] INTEGER OPTIONAL,
value2 [1 ] UTF8String OPTIONAL,
value3 [2] INTEGER OPTIONAL
}
@ASN1 SEQUENCE
public class MyObject extends DERRoot {
@ASN1 Integer
@ASN1 SEQUENCEField(position = 1 , optional = ASN I Optional.NotNull)
@ASN1Tag(number = 0, type = ASNI TagType .CONSTRUCTED)
private Integer valuel ;
//Type set on getter
@ASN1 SEQUENCEField(position = 2, optional = ASNI Optional.NotNull)
@ASN1Tag(number = 1 , type = ASNI TagType .CONSTRUCTED)
private String value2;
@ASN1 Integer
@ASN1 SEQUENCEField(position = 3, optional = ASN I Optional.NotNull)
@ASN1Tag(number = 2, type = ASNI TagType .CONSTRUCTED)
private int value3;
@Override
public void validate() {
}
public Integer getValuel () {
return valuel ;
}
public void setValuel (Integer valuel ) {
this. valuel = valuel ;
}
@ASN1 UTF8String
public String getValue2() {
return value2;
}
public void setValue2(String value2) {
this.value2 = value2;
}
public int getValue3() {
return value3;
}
public void setValue3(int value3) {
this.value3 = value3;
}
}
In dem Beispiel sind alle Felder optional. Durch zwei Integer-Variable wäre die Zuordnung nicht mehr eindeutig. Durch die Tags und ihre Nummer bleibt die Zuordnung jedoch erhalten.
Das Attribut number gibt dabei die Tag-Nummer an, während das Attribut type den Tag-Typ angibt, der in diesem Fall CONS TR UC TED ist. Sollte lediglich valuel mit dem Wert 100 gesetzt sein, so ergibt sich das ASN-Byte-Array: 3005A003020164.
Tags können aber auch direkt an Klassen definiert werden:
MyObject ::= [0] INTEGER
@ASN1 Integer
@ASN1Tag(number = 0, type = ASNI TagType.CONSTRUCTED)
public class MyObject extends DERRoot {
@ASN1TargetField
private Biginteger value;
public MyObject() {
super();
}
public MyObject(Biglnteger value) {
this. value = value;
}
public Biginteger getValue() {
return value;
}
public void setValue(Biglnteger value) {
this. value = value;
}
}
Auf diese Art und Weise kann die Klasse selbst dafür sorgen, einen eindeutigen Tag zu erhalten.
Obwohl normalerweise das doppelte Tagging erlaubt ist, sollte kein tatsächliches doppeltes Tagging erfolgen, wie beispielsweise, dass das Objekt MyObject in einer anderen
SEQUENCE nochmals getaggt wird. Insbesondere beim impliziten Tagging wird dann eine ASN1 -Exeption geworfen.
Analog zum CONSTRUCTED-Tag verhält es sich beim APPLICA 7/O/V-Tag :
MyObject ::= SEQUENCE {
valuel [APPLICATION 0] INTEGER OPTIONAL,
value2 [APPLICATION 1 ] UTF8String OPTIONAL,
value3 [APPLICATION 2] INTEGER OPTIONAL
}
@ASN1 SEQUENCE
public class MyObject extends DERRoot {
@ASN1 Integer
@ASN1 SEQUENCEField(position = 1 , optional = ASN1 Optional. NotNull)
@ASN1Tag(number = 0, type = ASNITagType.APPLICATION)
private Integer valuel ;
//Type set on getter
@ASN1 SEQUENCEField(position = 2, optional = ASN I Optional.NotNull) @ASN1Tag(number = 1 , type = ASNITagType.APPLICATION)
private String value2;
@ASN1 Integer
@ASN1 SEQUENCEField(position = 3, optional = ASN I Optional.NotNull) @ASN1Tag(number = 2, type = ASNITagType.APPLICATION)
private int value3;
public Integer getValuel () {
return valuel ;
}
public void setValuel (Integer valuel ) {
this. valuel = valuel ;
}
@ASN1 UTF8String
public String getValue2() {
return value2;
}
public void setValue2(String value2) {
this.value2 = value2;
}
public int getValue3() {
return value3;
}
public void setValue3(int value3) {
this.value3 = value3;
}
}
Das aus diesem Beispiel resultierende ASN-Byte-Array mit dem Wert 100 für das Feld valuel ist: 30055003020164
Auch im folgenden Fall können Klassen mit diesem Tag versehen werden:
MyObject ::= [APPLICATION 0] INTEGER
@ASN1 Integer
@ASN1Tag(number = 0, type = ASN UagType.APPLICATION)
public class MyObject extends DERRoot {
@ASN1TargetField
private Biginteger value;
public MyObject() {
super();
}
public MyObject(Biglnteger value) {
this. value = value;
}
public Biginteger getValue() {
return value;
}
public void setValue(Biglnteger value) {
this. value = value;
}
}
Obwohl normalerweise das doppelte Tagging erlaubt ist, sollte kein tatsächliches doppeltes Tagging erfolgen, wie beispielsweise, dass MyObject in einer anderen SEQUENCE nochmals getaggt wird. Insbesondere beim impliziten Tagging wird dann eine ASN1 - Exeption geworfen.
Häufig wird auf Grund von Speicherplatzmangel ein implizites Tagging angewendet. In diesem Fall wird der Universal-Tag des eigentlichen ASN1 -Objektes verschluckt. Dies spart mindestens zwei Bytes ein, wobei der Empfänger die ASN1 -Spezifikation des Objektes kennen sollte. Das implizite Tagging im ASN1 -Annotation-Framework funktioniert derart:
MyObject ::= [APPLICATION 0] INTEGER
@ASN1 Integer
@ASN1Tag(implicit = true, number = 0, type = ASNITagType.APPLICATION) public class MyObject extends DERRoot {
@ASN1TargetField
private Biginteger value;
}
Wird das Attribut implicit auf true gesetzt, so wird an dieser Stelle mit einem impliziten Tag gearbeitet. Bei einem Wert value von 100 ist das Umwandlungsergebnis: 500164.
In gleicher weise kann bei SEQUENCE aus dem oberen Beispielen vorgegangen werden.
Die entsprechenden Felder können eine Enumeration sein. Die Enumeration sollte einen für den ASN1 -Typ gültigen Wert zurückgeben. Folgendes Beispiel zeigt die Verwendung von Enumerationen:
MyValues ::= INTEGER { value1 (1 ), value2(2) }
MyObject ::= MyValues
@ASN1 Integer
@ASN1 Enum(findMethod = "getEnum", innerType = int.class, getMethod = "getValue") public class MyObject extends DERRoot {
public enum MyValues {
VALUE1 (1 ),
VALUE2(2);
private int value;
MyValues(int value) {
this. value = value;
}
public int getValue() {
return value;
}
public static MyValues getEnum(int value) {
for (MyValues e : values()) {
if (e.getValue() == value) {
return e;
}
}
throw new IHegalArgumentException("no enum found for: " + value);
}
}
@ASN1TargetField
private MyValues value;
public MyValues getValueQ {
return value;
}
public void setValue(MyValues value) {
this. value = value;
}
}
Im angeführten Beispiel ist zu erkennen, dass die Enumeration zwei Methoden umfasst: Die Methode getValue zum Ermitteln des tatsächlichen Enumeration-Wertes und die Methode getEnum zum Ermitteln der tatsächlichen Enumeration-Konstante über den Wert. Diese beiden Methoden werden in der Annotation ASNIEnum gesetzt. Das Attribut findMethod verlangt eine Methode, die den erwarteten Wert annimmt und versucht diesen in eine Enumeration-Konstante zurückzuführen. Das Attribut getMethod verlangt hingegen eine Methode, die einen tatsächlichen gültigen Wert zurückgibt, der durch die gesetzte
Enumeration-Konstante gegeben ist. Diese Annotation kann für ein Feld, beispielsweise innerhalb von SEQUENCE, verwendet werden.
Bit-Strings werden in der Regel verwendet, um den Zustand von mehreren Flags zu speichern. Dabei wird jedes Flag vom Typ boolean, das entweder gesetzt oder nicht gesetzt sein kann, in diesen Bit-String eingesetzt. Dies ist im ASN1 -Annotation-Framework wie folgt zu implementieren:
MyObject ::= BIT STRING (
valuel (0),
value2 (1 ))
@ASN1 ComplexBitString
public class MyObject extends DERRoot {
@ASN1 BitStringBit(bitPosition = 0)
private boolean valuel ;
@ASN1 BitStringBit(bitPosition = 1 )
private boolean value2;
@Override
public void validate() {
}
* @return the valuel
7
public boolean isValuel () {
return valuel ;
}
* @param valuel the valuel to SET
7
public void setValuel (boolean valuel ) {
this. valuel = valuel ;
}
* @return the value2
7
public boolean isValue2() {
return value2;
}
* @param value2 the value2 to set
7
public void setValue2(boolean value2) {
this.value2 = value2;
}
}
In diesem Beispiel werden die einzelnen Bits durch boolesche Parameter dargestellt. Wenn der ASN1 -Bytecode erzeugt wird, so wird ein Bytearray von ausreichender Länge erzeugt. Die nicht verwendeten Bytes werden als unusedbits markiert. Diese Berechnung kann über das Attribut calculateBitsPadding abgeschaltet werden. Sollte dieses Attribut auf false stehen, so wird unusedbits auf 0 gesetzt.
Vorteilhaft ist es, eine Basis für ein ASN1 -Objekt zu besitzen. Daher bietet das ASN1 - Annotation-Framework eine Möglichkeit, um die Vererbung zu verwenden. Diese kann auch über mehrere Klassen hinweg erfolgen. Der Basis-Typ eines Feldes kann zwar ein Interface oder eine abstrakte Klasse sein, jedoch sind die Annotationen ausschließlich an abstrakten Klassen oder dem Feld-Interface angeordnet, nicht jedoch an vererbten, darüber liegenden Interfaces. Dies wird durch die Mehrfachvererbung von Interfaces verhindert.
Im folgenden Beispiel ist eine einfache Vererbung dargestellt. Dabei wird als Basis ein Interface (Schnittstelle) verwendet, das die konkreten Klassen implementiert:
@ASN1Abstract(implementors = {
MyObject. class
})
public interface Mylnterface extends DERInterface {
void setValue(int value);
int getValue();
}
@ASN1 Integer
public class MyObject extends DERRoot implements Mylnterface {
@ASN1TargetField
private int value;
public MyObject() {
super();
}
public MyObject(int value) {
this. value = value;
}
}
@ASN1 SEQUENCE
public class MySEQUENCE extends DERRoot {
@ASN1 Complex
@ASN1 SEQUENCEField(position = 1 )
private Mylnterface value;
public Mylnterface getValue() {
return value;
}
public void setValue(Mylnterface value) {
this. value = value;
}
}
My Interface obj = new MyObject();
obj.setValue(100);
MySEQUENCE seq = new MySEQUENCE();
seq.setValue(obj);
Hierzu wird ein Interface (Schnittstelle) deklariert, das die benötigten Get-Methoden (Getter) und Set-Methoden (Setter) bereitstellt. Zusätzlich sollte das Interface von der Klasse DERInterface erben. Damit wird sichergestellt, dass das Objekt tatsächlich ein ASN1 -Objekt ist. Die Klasse DERRoot implementiert dieses Interface. Alle Klassen, die das deklarierte Interface implementieren, werden dort mittels der Annotation ASN1Abstract \m Attribut implementors in einer Liste gelistet. Dadurch erkennt der Parser, welche Klassen er berücksichtigen soll.
Die geerbten Objekte sollten eindeutig zuzuordnen sein, da ansonsten eine Ausnahme ASN1-Exception geworfen wird. Um dem Abhilfe zu schaffen, kann die Eindeutigkeit über einen Identifier (Identifikator) gewährleistet werden.
Bei der komplexen Vererbung von ASN1 -Klassen ist eine Struktur eines abstrakten Objektes nur oberflächlich bekannt. Das folgende Beispiel verdeutlicht dies:
MyBase CLASS ::= {
&value INTEGER,
&Type
}
MyAbstractObject {MyBase} ::= SEQUENCE {
valuel MyBase. &value,
value2 MyBase.&Type({@value1 })
MyObject ::= MyAbstractObject{1 , UTF8String}
@ASN1 SEQUENCE
@ASN1Abstract(implementors = {
MyObject.class,
})
public abstract class MyAbstractObject<T> extends DERRoot {
@ASN1 Integer
@ASN1 SEQUENCEField(position = 1 )
private Integer valuel ;
@ASN1 SEQUENCEField(position = 2)
protected T value2;
protected Integer getValuel () {
return valuel ;
}
protected void setValuel (Integer valuel ) {
this. valuel = valuel ;
}
}
public class MyObject extends MyAbstractObject<String> {
public MyObject() {
setValuel (1 );
}
@ASN1 UTF8String
public String getValue2() {
return value2;
}
public void setValue2(String value2) {
this.value2 = value2;
}
}
Hier ist zu erkennen, in welcher Weise die Basis als SEQUENCE markiert wird. Hierzu werden die bereits bekannten Felder valuel und value2 mit einer S£QL/£/VC£-Position versehen. Eine Besonderheit ist die Variable value2, deren Typ noch unbekannt ist und erst in der implementierenden Klasse an der Get-Methode des Feldes gesetzt wird. Das Feld sollte protected sein oder die Get-Methode sollte protected und überschreibbar sein.
An vielen Stellen wird allerdings mit einer sogenannten Set-Methode gearbeitet. Diese Strukturen lassen sich eleganter als das obige Beispiel schreiben:
MyClass ::= CLASS {
&id INTEGER
&Type
}
mylntegerClass MyClass ::= {{1 , INTEGER}} myStringClass MyClass ::= {{2, UTF8String}}
MyClassTable ::= {
mylntegerClass,
myStringClass
}
MyObject {MyClass: MyClassTable} ::= SEQUENCE { protocol MyClass. &id,
value MyClass. &Type,
comment PrintableString
}
@ASN10bjectClass
public class MyClass {
@ASN1 Integer
private int id;
@ASN10penType
private AnnotationType<?> type; public MyClass(int id, AnnotationType type) { this.id = id;
this.type = type;
}
public int getld() {
return id;
}
public void setld(int id) {
this.id = id;
}
public AnnotationType<?> getType() {
return type;
}
public void setType(AnnotationType<?> type) { this.type = type;
}
}
@ASN10bjectSET(baseObjectClass = MyClass.class)
public class MyClassTable {
public static final MyClass mylntegerClass = new MyClass(1 , new
ASN1 lntegerType());
public static final MyClass myStringClass = new MyClass(2, new
ASN1 UTF8StringType());
}
@ASN1 SEQUENCE
@ASN1 UseObjectSET(MyClassTable. class)
@ASN1Abstract(implementors = {MyObjectJnteger.class, MyObject_String. class}) public abstract class MyObject<T> extends DERRoot {
@ASN1 SEQUENCEField(position = 1 )
@ASN 10bjectClassl DReference("id")
private int protocol;
@ASN1 SEQUENCEField(position = 2)
@ASN10bjectClassTypeReference("type")
private T value;
@ASN1 SEQUENCEField(position = 3)
@ASN1 PrintableString
private String comment;
public T getValue() {
return value;
}
public void setValue(T value) {
this. value = value;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment= comment;
}
}
@ASN10bjectSetValue("MylntegerClass")
public class MyObjectJnteger extends ASN1 AbstractTestObjectWithSET<lnteger> { }
@ASN10bjectSetValue("MyStringClass")
public class MyObject_String extends ASN1AbstractTestObjectWithSET<String> { }
Hier werden alle aus dem Skript bekannten Objekte verwendet. Die Klasse dient der Beschreibung des Typs mittels einer ID, das Feld protocol wird auf id gemappt und das Feld value wird auf den ASN1 -Typ gemappt, der abhängig von der Identifikation ID ist.
Dementsprechend existiert eine Ableitung für den Fall Integer und eine für den Fall String.
Diese werden mit der Annotation ASN1 ObjectSetValue versehen, die beschreibt, welcher ObjectSetValue verwendet werden soll. Diese Angabe sollte sich mit den Annotation-Werten der Super-Klasse decken.
Um den Typen anzugeben, wird dieser mit der Annotation ASNIOpenType markiert, der zudem vom Typ AnnotationType ist. AnnotationType ist ein Typ, der eine Annotation repräsentiert. Beispielsweise ist ein ASNIIntegerType die Repräsentation der ASNIInteger- Annotation. Der Typ kann einfach mittels der Methode toAnnotation in eine gültige
Annotation umgewandelt werden. Innerhalb des Frameworks werden diese Typen verwendet, um bei einer ASN1 -Klassendefinition den ASN1 -Typen als Typ mitzugeben. Den ASN1 -Annotation-Typen können aber auch die gesamten Attribute der bekannten ASN1 - Typ-Annotationen über den Konstruktor oder über Set-Methoden mitgegeben werden.
Manchmal werden im Rahmen der komplexen Vererbung Identifier vergeben, die ein Objekt eindeutig kennzeichnen. Dies zeigt folgendes Beispiel:
@ASN1 SEQUENCE
@ASN1Abstract(implementors = {
DERChipAuthenticationlnfo. class,
DERTerminalAuthenticationlnfo. class,
DERChipAuthenticationPublicKeylnfo. class
})
public abstract class DERSecuritylnfo<Required, Optional> extends DERRoot { @ASN10bjectldentifier
@ASN1 SEQUENCEField(position = 0)
@ASN1 ldentifier(matchMethod = "isMatch")
protected DERObjectldentifier protocolOID;
//Type definition in child Implementation
@ASN1 SEQUENCEField(position = 1 )
private Required required;
//Type definition in child Implementation
@ASN1 SEQUENCEField(position = 2, optional = ASN I Optional.NotNull) private Optional optional;
@Override
public void validate() {
if (protocolOID == null)
throw new SecuritylnfoValidationException("Cannot create or parse
DERSecuritylnfo!",
ASN1 Validation Exception.createAIIMustNotNullException("protocolOID"));
}
protected DERSecuritylnfo() {
}
protected Required getRequired() {
return required;
}
protected void setRequired(Required required) {
this. required = required;
}
protected Optional getOptional() {
return optional;
}
protected void setOptional(Optional optional) {
this. optional = optional;
}
// Check the matching
protected abstract boolean isMatch(String id);
}
public class DERChipAuthenticationlnfo extends
DERSecuritylnfo<org.bouncycastle.asn1.ASN1 Integer, lnteger> {
public enum ChipAuthenticationProtocol {
CA_DH_3DES_CBC_CBC(BSIIdentifier.lD_CA_DH_3DES_CBC_CBC), CA_ECDH_3DES_CBC_CBC(BSIIdentifier.lD_CA_ECDH_3DES_CBC_CBC); public static ChipAuthenticationProtocol fromOID(String oid) {
for (ChipAuthenticationProtocol item : ChipAuthenticationProtocol. valuesQ) {
if (item.getold().equals(oid))
return item;
}
throw new SecuritylnfoOtherException("Cannot find type for OID " + oid);
}
public static boolean checkOID(String oid) {
for (ChipAuthenticationProtocol item : ChipAuthenticationProtocol.values()) { if (item.getold().equals(oid))
return true;
}
return false;
}
private String oid;
private ChipAuthenticationProtocol(String oid) {
this.old = oid;
}
public String getold() {
return oid;
}
}
public DERChipAuthenticationlnfo() {
}
public DERChipAuthenticationlnfo(ChipAuthenticationProtocol protocol) { super();
this.protocolOID = new DERObjectldentifier(protocol.getold());
super.setOptional(null);
super.setRequired(new org.bouncycastle.asn1 .ASN1 lnteger(1 ));
}
public DERChipAuthenticationlnfo(ChipAuthenticationProtocol protocol, int keyld) { super();
this.protocolOID = new DERObjectldentifier(protocol.getold());
super.setOptional(keyld);
super.setRequired(new org.bouncycastle.asn1 .ASN1 lnteger(1 ));
}
public ChipAuthenticationProtocol getProtocol() {
return ChipAuthenticationProtocol.fromOID(this.protocolOID.getld());
}
public void setProtocol(ChipAuthenticationProtocol protocol) {
this.protocolOID = new DERObjectldentifier(protocol.getold());
}
public Integer getKeyld() {
return super.getOptional();
}
public void setKeyld(lnteger keyld) {
super.setOptional(keyld);
}
//Additional annotation for optional
@Override
©ASNI Integer
protected Integer getOptional() {
return super.getOptional();
}
//Additional annotation for required
@Override
©ASNI Integer
protected org.bouncycastle.asn1 .ASN1 Integer getRequired() {
return super.getRequired();
}
@Override
protected void setRequired(org.bouncycastle.asn1.ASN1 Integer derlnteger) { super.setRequired(derlnteger);
}
@Override
protected void setOptional(lnteger integer) {
super.setOptional(integer);
}
@Override
protected boolean isMatch(String id) {
return ChipAuthenticationProtocol.checkOID(id);
}
@Override
public void validate() {
super.validate();
if (!super.getRequired().equals(new org.bouncycastle.asn1 .ASN1 lnteger(1 ))) { throw new SecuritylnfoValidationException("required should be 1 , but was: " + super.getRequired());
}
}
}
public class DERChipAuthenticationPublicKeylnfo extends
DERSecuritylnfo<DERSubjectPublicKeylnfo, lnteger> {
public enum ChipAuthenticationPublicKeyProtocol {
PK_DH(BSIIdentifier.lD_PK_DH), PK_ECDH(BSIIdentifier.lD_PK_ECDH); public static ChipAuthenticationPublicKeyProtocol fromOID(String oid) { for (ChipAuthenticationPublicKeyProtocol item :
ChipAuthenticationPublicKeyProtocol.valuesO) {
if (item.getold().equals(oid))
return item;
}
throw new SecuritylnfoOtherException("Cannot find type for OID " + oid);
}
public static boolean checkOID(String oid) {
for (ChipAuthenticationPublicKeyProtocol item :
ChipAuthenticationPublicKeyProtocol.valuesO) {
if (item.getold().equals(oid))
return true;
}
return false;
}
private String oid;
private ChipAuthenticationPublicKeyProtocol(String oid) {
this.old = oid;
}
public String getold() {
return oid;
}
}
@Override
@ASN1 Complex
protected DERSubjectPublicKeylnfo getRequired() {
return super.getRequired(); //To change body of overridden methods use File | SETtings | File Templates.
}
@Override
protected void setRequired(DERSubjectPublicKeylnfo derSubjectPublicKeylnfo) { super.setRequired(derSubjectPublicKeylnfo); //To change body of overridden methods use File | SETtings | File Templates.
}
@Override
@ASN1 Integer
protected Integer getOptional() {
return super.getOptional(); //To change body of overridden methods use File | SETtings | File Templates.
}
@Override
protected void setOptional(lnteger integer) {
super.setOptional(integer); //To change body of overridden methods use File | Settings | File Templates.
}
public DERChipAuthenticationPublicKeylnfo() {
}
public DERChipAuthenticationPublicKeylnfo(ChipAuthenticationPublicKeyProtocol protocol,
DERSubjectPublicKeylnfo subjectPublicKeylnfo) {
super();
this.protocolOID = new DERObjectldentifier(protocol.getold());
super.setRequired(subjectPublicKeylnfo);
super.setOptional(null);
}
public DERChipAuthenticationPublicKeylnfo(ChipAuthenticationPublicKeyProtocol protocol,
DERSubjectPublicKeylnfo subjectPublicKeylnfo, int keyld) {
super();
this.protocolOID = new DERObjectldentifier(protocol.getold());
super.setRequired(subjectPublicKeylnfo);
super.setOptional(keyld);
}
@Override
protected boolean isMatch(String id) {
return ChipAuthenticationPublicKeyProtocol.checkOID(id);
}
public ChipAuthenticationPublicKeyProtocol getProtocol() {
return ChipAuthenticationPublicKeyProtocol.fromOID(protocolOID.getld());
} public void setProtocol(ChipAuthenticationPublicKeyProtocol protocol) {
this.protocolOID = new DERObjectldentifier(protocol.getold());
}
public DERSubjectPublicKeylnfo getSubjectPublicKeylnfo() {
return super.getRequired();
}
public void setSubjectPublicKeylnfo(DERSubjectPublicKeylnfo subjectPublicKeylnfo)
{
super.setRequired(subjectPublicKeylnfo);
}
public Integer getKeyld() {
return super.getOptional();
}
public void setKeyld(lnteger keyld) {
super.setOptional(keyld);
}
}
public class DERTerminalAuthenticationlnfo extends
DERSecuritylnfo<org.bouncycastle.asn1.ASN1 Integer, DERFilelD> {
public enum TerminalAuthenticationProtocol {
TA(BSIIdentifier.lD_TA);
public static TerminalAuthenticationProtocol fromOID(String oid) {
for (TerminalAuthenticationProtocol item : TerminalAuthenticationProtocol. valuesQ)
if (item.getold().equals(oid))
return item;
}
throw new SecuritylnfoOtherException("Cannot find type for OID " + oid);
}
public static boolean checkOID(String oid) {
for (TerminalAuthenticationProtocol item : TerminalAuthenticationProtocol. values()) if (item.getold().equals(oid))
return true;
} return false;
}
private String oid;
private TerminalAuthenticationProtocol(String oid) {
this.old = oid;
}
public String getold() {
return oid;
}
}
public DERTerminalAuthenticationlnfo(TerminalAuthenticationProtocol protocol) { this.protocolOID = new DERObjectldentifier(protocol.getold());
super.setOptional(null);
super.setRequired(new org.bouncycastle.asn1 .ASN1 lnteger(1 ));
}
public DERTerminalAuthenticationlnfo(TerminalAuthenticationProtocol protocol, DERFilelD fileld) {
super();
this.protocolOID = new DERObjectldentifier(protocol.getold());
super.setOptional(fileld);
super.setRequired(new org.bouncycastle.asn1 .ASN1 lnteger(1 ));
}
public TerminalAuthenticationProtocol getProtocolQ {
return TerminalAuthenticationProtocol.fromOID(protocolOID.getld());
}
public void setProtocol(TerminalAuthenticationProtocol protocol) {
this.protocolOID = new DERObjectldentifier(protocol.getold());
}
public DERTerminalAuthenticationlnfo() {
}
@Override
protected boolean isMatch(String id) {
return TerminalAuthenticationProtocol.checkOID(id);
}
public DERFilelD getFileld() {
return super.getOptional();
}
public void setFileld(DERFilelD fileld) {
super.setOptional(fileld);
}
@Override
@ASN1 Integer
protected org.bouncycastle.asn1.ASN1 Integer getRequired() {
return super.getRequired();
}
@Override
protected void setRequired(org.bouncycastle.asn1.ASN1 Integer derlnteger) { super.setRequired(derlnteger);
}
@Override
@ASN1 Complex
protected DERFilelD getOptional() {
return super.getOptional(); //To change body of overridden methods use File | Settings | File Templates.
}
@Override
protected void setOptional(DERFilelD derFilelD) {
super.setOptional(derFilelD); //To change body of overridden methods use File |
Settings | File Templates.
}
@Override
public void validate() {
super.validate();
if (!super.getRequired().equals(new org.bouncycastle.asn1.ASN1 lnteger(1 ))) { throw new SecuritylnfoValidationException("required should be 1 , but was: " + super.getRequired());
}
}
}
In diesem Beispiel ist zu erkennen, dass alle geerbten Klassen gleich aufgebaut sind und faktisch keine Eindeutigkeit mehr existiert. Dies wird behoben, indem die Annotation ASNIIdentifier verwendet wird, um das Objekt eindeutig zu identifizieren und damit eine Prüfung auf das markierte Feld erfolgen kann. Mit dem Attribut matchMethod wird eine Methode festgelegt, die überprüft, ob die angegebenen Eingangsdaten zu dem Objekt passen. Damit wird die Eindeutigkeit des Objektes gewahrt.
Manchmal werden in einer ASN1 -Struktur keine Angaben über weitere Elemente beispielsweise innerhalb von SEQUENCE gemacht. Im folgenden Beispiel wird eine solche ASN1 -Future-Extension-Deklaration durchgeführt:
MyObject ::= SEQUENCE {
valuel INTEGER,
}
@ASN1 SEQUENCE
public class MyObject extends DERRoot {
@ASN1 Integer
@ASN1 SEQUENCEField(position = 0)
private int valuel ;
@ASN1 FutureExtension(createMethod = "create", parseMethod = "_parse")
@ASN1 SEQUENCEField(position = 1 )
private List<lnteger> value2 = new ArrayList<lnteger>();
protected DEREncodable[] create(Object value) throws lOException {
DEREncodable[] result = new DEREncodable[value2.size()];
for (int i = 0; i < result. length; i++) {
result[i] = new DERApplicationSpecific(false, 0x2E, new DERInteger(value2.get(i)));
}
return result;
}
protected void _parse(DEREncodable encodable) throws lOException {
if (!(encodable instanceof DERApplicationSpecific))
throw new ASN1 ParseException("Cannot parse object! Must be an integer!");
DERApplicationSpecific app = (DERApplicationSpecific) encodable;
if (app.getApplicationTagO != 0x2E)
throw new ASN1 ParseException("Wrong application number!");
this.add(((DERInteger)
app.getObject(ASN10bject.lNTEGER)).getValue().intValue());
}
public void add(int i) {
value2.add(i);
valuel = value2.size();
}
public void remove(int i) {
value2.remove((Object) i);
valuel = value2.size();
}
public int get(int index) {
return value2.get(index);
}
}
Bei der FyfyreExfens/on-Annotation wird sowohl die create- als auch die parse-Methode über die Attribute createMethod oder parseMethod angegeben. In diesen Methoden findet die eigentliche Umwandlung gemäß ASN1 oder die Umwandlung in Datentypen statt. Dabei wird die im obigen Beispiel aufgeführte Methodensignatur bis auf die Methodennamen identisch übernommen. Bei dem FutureExtension-Typ wlrd keine Tag-Annotation
angegeben. Der Tag wird, wie im obigen Beispiel, davorgehängt.
Alle in der ASN1 -Sprache existierenden Constraints können bei Bedarf über die
Annotationen mit angegeben werden.
Fig. 8 zeigt dazu die möglichen Annotationen durch das Framework. Folgendes Beispiel verdeutlicht die Anwendung dieser Vorgehensweise: MyObject ::= INTEGER(0..10)
@ASN1 lnteger(valueRangeConstraint = @ASN1ValueRangeConstraint(minimum = 1 , maximum = 10))
public class MyObject extends DERRoot {
@ASN1TargetField
private Biginteger value;
}
Sollte die Integer-Variable außerhalb der Wertebereiche liegen, so wird eine
ASN1 ValidationException geworfen.
Constraints (Beschränkungen) können über mehrere Objekte hinweg neu gesetzt werden. Dies spielt bei der Vererbung von Klassen eine Rolle. Folgendes Beispiel verdeutlicht die Vorgehensweise:
MyAbstractObject ::= UTF8String FROM("A".."Z");
MyBaseObject ::= MyAbstractObject SIZE(5..10);
MyObject ::= [APPLICATION 10] MyBaseObject;
@ASN1 UTF8String(patternConstraint = @ASN1 PatternConstraint("[A-Z]*")) public abstract class MyAbstractObject extends DERRoot {
@ASN1TargetField
private String value;
}
@ASN1 Constraint(sizeConstraint = @ASN1 SizeConstraint(minimum = 5, maximum = 10))
public class MyBaseObject extends MyAbstractObject {
}
@ASN1 Tag(type = ASNI TagType.Application, number = 10)
public final class MyObject extends MyBaseObject {
}
Hier werden über mehrere Klassengenerationen unterschiedliche Constraints zusätzlich den einzelnen Kind-Klassen zugeordnet. Dadurch können Constraints von Generation zu Generation angereichert werden. Beim Überschreiben von Constraints wird in jedem Fall eine ASN1 -Exception geworfen.
Constraints können aber auch in Klassen angewendet werden:
MyClass ::= CLASS {
&id INTEGER
&Type
}
MylntegerClass MyClass ::= {1 , INTEGER(0..10)}
MyStringClass MyClass ::= {2, UTF8String SIZE(20..40)}
MyClassTable ::= {
MylntegerClass,
MyStringClass
}
MyObject {MyClass:MyClassTable} ::= SEQUENCE {
protocol MyClass. &id,
value MyClass. &Type,
comment PrintableString
}
@ASN10bjectClass
public class MyClass {
@ASN1 Integer
private int id;
@ASN10penType
private AnnotationType<?> type;
public MyClass(int id, AnnotationType type) {
this.id = id;
this.type = type;
}
public int getld() {
return id;
}
public void setld(int id) {
this.id = id;
}
public AnnotationType<?> getType() {
return type;
} public void setType(AnnotationType<?> type) {
this.type = type;
}
}
@ASN10bjectSET(baseObjectClass = MyClass.class)
public class MyClassTable {
public static final MyClass mylntegerClass;
public static final MyClass myStringClass;
static {
ASN1 IntegerType integerType = new ASN1 lntegerType();
integerType.setValueRangeConstraint(new ASN1ValueRangeConstraintType(0, 10));
ASN1 UTF8StringType utf8Type = new ASN1 UTF8StringType();
utf8Type.setSizeConstraint(new ASN 1 SizeConstraintType(20, 40));
mylntegerClass = new MyClass(1 , integerType);
myStringClass = new MyClass(2, utf8Type);
}
}
@ASN1 SEQUENCE
@ASN1 UseObjectSET(MyClassTable. class)
@ASN1Abstract(implementors = {MyObject_lnteger.class, MyObject_String. class}) public abstract class MyObject<T> extends DERRoot {
@ASN1 SEQUENCEField(position = 1 )
@ASN10bjectClasslDReference("id")
private int protocol;
@ASN1 SEQUENCEField(position = 2)
@ASN10bjectClassTypeReference("type")
private T value;
@ASN1 SEQUENCEField(position = 3)
@ASN1 PrintableString
private String comment;
public T getValue() {
return value;
}
public void setValue(T value) {
this. value = value;
} public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment= comment;
}
}
@ASN10bjectSETValue("MylntegerClass")
public class MyObjectJnteger extends ASN1 AbstractTestObjectWithset<lnteger> { }
@ASN10bjectSETValue("MyStringClass")
public class MyObject_String extends ASN1AbstractTestObjectWithSET<String> { }
In diesem Beispiel wird eine typenspezifische Constraint-Auspragung innerhalb der ASN1 - Klassen verwendet.
Alle in Verbindung mit einzelnen Ausführungsformen der Erfindung erläuterten Merkmale können in unterschiedlicher Kombination in dem erfindungsgemäßen Gegenstand vorgesehen sein, um gleichzeitig deren vorteilhafte Wirkungen zu realisieren.
Der Schutzbereich der vorliegenden Erfindung ist durch die Ansprüche gegeben und wird durch die in der Beschreibung erläuterten oder die in den Figuren gezeigten Merkmale nicht beschränkt.
BEZUGSZEICHENLISTE
Ausgangsdaten
Zieldaten
Annotations
AS N 1 - F ra m ewo rk/ U mwa n d I er
Funktionsaufruf
Verfahrensschritte
ASN1 -Frameworks
Handler
Handler
ASNI Encodable
DERRoot
DERinterface
CreationUtility
ParsingUtility
ASNI XXXParsingHandler
ASN1 Abstract Simple Type
Interface
ASN 1 Handler
convert Object
ASN1 Abstract Simple Type
ASN 1 Creation Handler
sd ASN1 Simple Creation
Creation Root Handler
Creation Utility
Verfahrenschritt
Verfahrenschritt
Verfahrenschritt
Verfahrenschritt
sd ASN1 Complex Creation
Sequence Handler
Verfahrenschritt
Verfahrenschritt
Verfahrenschritt
Verfahrenschritt
Verfahrenschritt
Verfahrenschritt
Verfahrenschritt
act ASN1
Finde ASN1 -Type-Annotation
Handle einfachen Typ
Handle Sequences/Sets
Finde alle Felder mit ASN1 -Type-Annotation
Abfrage
Creation/Parsing
Handle SEQ-UENCEO
Handle einfachen Typ
Abfrage
Abfrage
Ende
Ende