blob: 8bbb47f627e537e359daf8de66bdc30ff60b4a5f [file] [log] [blame]
Title: Kerby ASN1
Notice: Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
.
http://www.apache.org/licenses/LICENSE-2.0
.
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
# Kerby ASN1
### ASN1 hierarcy
![](hierarchy.png)
### A ASN1 parser with easy and simple API
// encoding
Asn1Integer aValue = new Asn1Integer(8899);
byte[] encoded = aValue.encode();
// decoding
byte[] contentToDecode = ...
Asn1Integer decodedValue = new Asn1Integer();
decodedValue.decode(contentToDecode);
Integer value = decodedValue.getValue();
### Data-driven ASN1 encoding/decoding framework and parser
With the following definition from Kerberos protocol
AuthorizationData ::= SEQUENCE OF SEQUENCE {
ad-type [0] Int32,
ad-data [1] OCTET STRING
}
You can model AuthzDataEntry as follows
public class AuthorizationDataEntry extends KrbSequenceType {
/**
* The possible fields
*/
protected enum AuthorizationDataEntryField implements EnumType {
AD_TYPE,
AD_DATA;
/**
* {@inheritDoc}
*/
@Override
public int getValue() {
return ordinal();
}
/**
* {@inheritDoc}
*/
@Override
public String getName() {
return name();
}
}
/** The AuthorizationDataEntry's fields */
private static Asn1FieldInfo[] fieldInfos = new Asn1FieldInfo[] {
new ExplicitField(AuthorizationDataEntryField.AD_TYPE, Asn1Integer.class),
new ExplicitField(AuthorizationDataEntryField.AD_DATA, Asn1OctetString.class)
};
/**
* Creates an AuthorizationDataEntry instance
*/
public AuthorizationDataEntry() {
super(fieldInfos);
}
/**
* @return The AuthorizationType (AD_TYPE) field
*/
public AuthorizationType getAuthzType() {
Integer value = getFieldAsInteger(AuthorizationDataEntryField.AD_TYPE);
return AuthorizationType.fromValue(value);
}
/**
* Sets the AuthorizationType (AD_TYPE) field
* @param authzType The AuthorizationType to set
*/
public void setAuthzType(AuthorizationType authzType) {
setFieldAsInt(AuthorizationDataEntryField.AD_TYPE, authzType.getValue());
}
/**
* @return The AuthorizationType (AD_DATA) field
*/
public byte[] getAuthzData() {
return getFieldAsOctets(AuthorizationDataEntryField.AD_DATA);
}
/**
* Sets the AuthorizationData (AD_DATA) field
* @param authzData The AuthorizationData to set
*/
public void setAuthzData(byte[] authzData) {
setFieldAsOctets(AuthorizationDataEntryField.AD_DATA, authzData);
}
}
And then define AuthorizationData simply
public class AuthorizationData extends KrbSequenceOfType<AuthorizationDataEntry> {
}
Then you can process with above definitions, encode and decode, without caring about the details.
Think about how to implement the following more complex and pratical sample from [ITU-T Rec. X.680 ISO/IEC 8824-1](http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf):
A.1 ASN.1 description of the record structure
The structure of the hypothetical personnel record is formally described below using ASN.1 specified in
ITU-T Rec. X.680 | ISO/IEC 8824-1 for defining types.
PersonnelRecord ::= [APPLICATION 0] IMPLICIT SET {
Name Name,
title [0] VisibleString,
number EmployeeNumber,
dateOfHire [1] Date,
nameOfSpouse [2] Name,
children [3] IMPLICIT
SEQUENCE OF ChildInformation DEFAULT {}
}
ChildInformation ::= SET {
name Name,
dateOfBirth [0] Date
}
Name ::= [APPLICATION 1] IMPLICIT SEQUENCE {
givenName VisibleString,
initial VisibleString,
familyName VisibleString
}
EmployeeNumber ::= [APPLICATION 2] IMPLICIT INTEGER
Date ::= [APPLICATION 3] IMPLICIT VisibleString -- YYYYMMDD
```
Similarly as above, we can have (from the unit test codes):
public class PersonnelRecord extends Asn1TaggingSet {
protected enum PersonnelRecordField implements EnumType {
NAME,
TITLE,
NUMBER,
DATE_OF_HIRE,
NAME_OF_SPOUSE,
CHILDREN;
@Override
public int getValue() {
return ordinal();
}
@Override
public String getName() {
return name();
}
}
static Asn1FieldInfo[] fieldInfos = new Asn1FieldInfo[] {
new ExplicitField(PersonnelRecordField.NAME, -1, Name.class),
new ExplicitField(PersonnelRecordField.TITLE, 0, Asn1VisibleString.class),
new ExplicitField(PersonnelRecordField.NUMBER, -1, EmployeeNumber.class),
new ExplicitField(PersonnelRecordField.DATE_OF_HIRE, 1, Date.class),
new ExplicitField(PersonnelRecordField.NAME_OF_SPOUSE, 2, Name.class),
new ImplicitField(PersonnelRecordField.CHILDREN, 3, Children.class)
};
public PersonnelRecord() {
super(0, fieldInfos, true, true);
}
public void setName(Name name) {
setFieldAs(PersonnelRecordField.NAME, name);
}
public Name getName() {
return getFieldAs(PersonnelRecordField.NAME, Name.class);
}
public void setTitle(String title) {
setFieldAs(PersonnelRecordField.TITLE, new Asn1VisibleString(title));
}
public String getTitle() {
return getFieldAsString(PersonnelRecordField.TITLE);
}
public void setEmployeeNumber(EmployeeNumber employeeNumber) {
setFieldAs(PersonnelRecordField.NUMBER, employeeNumber);
}
public EmployeeNumber getEmployeeNumber() {
return getFieldAs(PersonnelRecordField.NUMBER, EmployeeNumber.class);
}
public void setDateOfHire(Date dateOfHire) {
setFieldAs(PersonnelRecordField.DATE_OF_HIRE, dateOfHire);
}
public Date getDateOfHire() {
return getFieldAs(PersonnelRecordField.DATE_OF_HIRE, Date.class);
}
public void setNameOfSpouse(Name spouse) {
setFieldAs(PersonnelRecordField.NAME_OF_SPOUSE, spouse);
}
public Name getNameOfSpouse() {
return getFieldAs(PersonnelRecordField.NAME_OF_SPOUSE, Name.class);
}
public void setChildren(Children children) {
setFieldAs(PersonnelRecordField.CHILDREN, children);
}
public Children getChildren() {
return getFieldAs(PersonnelRecordField.CHILDREN, Children.class);
}
public static class Children extends Asn1SequenceOf<ChildInformation> {
public Children(ChildInformation ... children) {
super();
for (ChildInformation child : children) {
addElement(child);
}
}
public Children() {
super();
}
}
public static class ChildInformation extends Asn1SetType {
protected enum ChildInformationField implements EnumType {
CHILD_NAME,
DATE_OF_BIRTH;
@Override
public int getValue() {
return ordinal();
}
@Override
public String getName() {
return name();
}
}
static Asn1FieldInfo[] tags = new Asn1FieldInfo[] {
new ExplicitField(ChildInformationField.CHILD_NAME, -1, Name.class),
new ExplicitField(ChildInformationField.DATE_OF_BIRTH, 0, Date.class)
};
public ChildInformation() {
super(tags);
}
public void setName(Name name) {
setFieldAs(ChildInformationField.CHILD_NAME, name);
}
public Name getName() {
return getFieldAs(ChildInformationField.CHILD_NAME, Name.class);
}
public void setDateOfBirth(Date date) {
setFieldAs(ChildInformationField.DATE_OF_BIRTH, date);
}
public Date getDateOfBirth() {
return getFieldAs(ChildInformationField.DATE_OF_BIRTH, Date.class);
}
}
public static class Name extends Asn1TaggingSequence {
protected enum NameField implements EnumType {
GIVENNAME,
INITIAL,
FAMILYNAME;
@Override
public int getValue() {
return ordinal();
}
@Override
public String getName() {
return name();
}
}
static Asn1FieldInfo[] tags = new Asn1FieldInfo[] {
new ExplicitField(NameField.GIVENNAME, -1, Asn1VisibleString.class),
new ExplicitField(NameField.INITIAL, -1, Asn1VisibleString.class),
new ExplicitField(NameField.FAMILYNAME, -1, Asn1VisibleString.class)
};
public Name() {
super(1, tags, true, true);
}
public Name(String givenName, String initial, String familyName) {
this();
setGivenName(givenName);
setInitial(initial);
setFamilyName(familyName);
}
public void setGivenName(String givenName) {
setFieldAs(NameField.GIVENNAME, new Asn1VisibleString(givenName));
}
public String getGivenName() {
return getFieldAsString(NameField.GIVENNAME);
}
public void setInitial(String initial) {
setFieldAs(NameField.INITIAL, new Asn1VisibleString(initial));
}
public String getInitial() {
return getFieldAsString(NameField.INITIAL);
}
public void setFamilyName(String familyName) {
setFieldAs(NameField.FAMILYNAME, new Asn1VisibleString(familyName));
}
public String getFamilyName() {
return getFieldAsString(NameField.FAMILYNAME);
}
}
public static class EmployeeNumber extends Asn1Tagging<Asn1Integer> {
public EmployeeNumber(Integer value) {
super(2, new Asn1Integer(value), true, true);
}
public EmployeeNumber() {
super(2, new Asn1Integer(), true, true);
}
}
public static class Date extends Asn1Tagging<Asn1VisibleString> {
public Date(String value) {
super(3, new Asn1VisibleString(value), true, true);
}
public Date() {
this(null);
}
}
}
### Asn1 API and parsing/dumping facilities
* ASN1 dumping tool to help analyze ASN1 encoding stream or packet. It can be used to exercise the framework with all kinds of testing binary inputs.
* The shortcut API for ASN1 parser, encoding, decoding.
### Notes
* Extensive tests coverage for BER & DER encoding and decoding
* Fully self-contained, no extra dependency
### License
Apache V2 License