Search code examples
javabouncycastleasn.1

Bouncy Castle ASN1 retrieving objects from BERTaggedObject


I am using Bouncy Castle to decode BER X.690 ASN.1 files.

Here is part of ASN.1 mapping file:

CallEventRecord ::= CHOICE
{
    sgsnPDPRecord [20] SGSNPDPRecord,
}

SGSNPDPRecord ::= SET
{
    recordType [0] CallEventRecordType,
    networkInitiation [1] NetworkInitiatedPDPContext OPTIONAL,
    servedIMSI [3] IMSI,
    servedIMEI [4] IMEI OPTIONAL
}

I am able to successfully read object from input file. And calling toString method on BERTaggedObject berObj gives:

[20][[0]#12, [3]#12191031148270f3, [4]#5302816004686062,]

You can see SGSNPDPRecord's tag [20], [0]#12 is recordType and it's content, everything is done well here I checked it with ASN1 Dump Utility. I am stuck with extracting SGSNPDPRecord member fields (recordType, networkInititation, etc).

I am not sure how should I extract fields and their berTags from BERTaggedObject berObj.

public class SGSNPDPRecord extends ASN1Object
{
Integer recordType;
Boolean networkInitiation;
String servedIMSI;
String servedIMEI;

private static int SGSNPDP_RECORD_BER_TAG = 20;

public SGSNPDPRecord(BERTaggedObject berObj) throws IOException {

        int tagNo = berObj.getTagNo();

        // Returns tag number 20, this one is OK
        if (tagNo != SGSNPDP_RECORD_BER_TAG )
        {
            System.out.println("Invalid Tag Number!");
            return;
        }

        // How to get here someObject that will check BER Tags of primitive fields recordType, networkInitiation ... and read content from the specific ber tag
        switch ( someObj.getApplicationTag() ) 
        {
            case 0: 
                this.recordType = new Integer( someObj.getContents()[0] );
                break;
            case 1:
                this.networkInitiation = new Boolean(new String( someObj.getContents()[0], "UTF-8"));
                break;
            case 3: 
                this.servedIMSI = new String(someObj.getContents(), "UTF-8");
                break;
            case 4: 
                this.servedIMEI = new String(someObj.getContents(), "UTF-8");
                break;
            default:
                break;
        }
}

@Override
public ASN1Primitive toASN1Primitive()
{
    return null;
}

}


Solution

  • I'm using BouncyCastle 1.56. If you're using a version <= 1.46, the code might not be the same, because in version 1.47 there were lots of significant changes in the API.

    First I've got the data you provided in the comments and built the tagged object corresponding to CallEventRecord:

    String s = "B480800112830812191031925895F0840853344080218389200000";
    ASN1InputStream in = new ASN1InputStream(Hex.decode(s));
    BERTaggedObject callEventRecord = (BERTaggedObject) in.readObject();
    in.close();
    

    I've just printed the tag and the content, just to make sure it's the same as yours:

    System.out.println(callEventRecord.getTagNo()); // 20
    System.out.println(callEventRecord.getObject()); // [[0]#12, [3]#12191031925895f0, [4]#5334408021838920]
    

    The output:

    20
    [[0]#12, [3]#12191031925895f0, [4]#5334408021838920]

    So, the tag is correct (20), and the content matches the same structure. Let's move on.


    I've just checked the value of callEventRecord.getObject().getClass() and it's a org.bouncycastle.asn1.BERSequence, which (according to the ASN.1 definition above) corresponds to SGSNPDPRecord. Then I looped through its elements, just to check their types:

    // get the SGSNPDPRecord
    BERSequence sgsnPDPRecord = (BERSequence) callEventRecord.getObject();
    for (int i = 0; i < sgsnPDPRecord.size(); i++) {
        System.out.println(sgsnPDPRecord.getObjectAt(i).getClass());
    }
    

    The result was 3 elements, all with the type org.bouncycastle.asn1.DERTaggedObject. Then I modified the loop to check the contents of each one:

    for (int i = 0; i < sgsnPDPRecord.size(); i++) {
        DERTaggedObject obj = (DERTaggedObject) sgsnPDPRecord.getObjectAt(i);
        // get the value with obj.getObject()
        switch (obj.getTagNo()) {
            case 0: // CallEventRecordType
                break;
            case 1: // NetworkInitiatedPDPContext
                break;
            case 3: // IMSI
                break;
            case 4: // IMEI
                break;
            default:
                break;
        }
    }
    

    Inside the loop, you just call obj.getObject() to get the corresponding value for each tag. In my test, all elements were instances of org.bouncycastle.asn1.DEROctetString, but only with the ASN.1 definition above I can't tell how each field should be handled.

    So, you should get the corresponding value with obj.getObject() and treat this value according to each field's definition.