Bouncy Castle ASN1 从 BERTaggedObject 检索对象

Bouncy Castle ASN1 retrieving objects from BERTaggedObject

我正在使用 Bouncy Castle 解码 BER X.690 ASN.1 文件。

这是 ASN.1 映射文件的一部分:

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

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

我能够从输入文件中成功读取对象。在 BERTaggedObject berObj 上调用 toString 方法给出:

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

可以看到SGSNPDPRecord的tag [20][0]#12是recordType和它的内容,这里一切都很好我用ASN1 Dump Utility检查了一下。 我坚持提取 SGSNPDPRecord 成员字段(recordTypenetworkInititation 等)。

我不确定如何从 BERTaggedObject berObj.

中提取字段及其 berTag
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;
}

}

我正在使用 BouncyCastle 1.56。如果您使用的版本 <= 1.46,代码可能不一样,因为在版本 1.47 中有 lots of significant changes in the API.

首先我得到了你在评论中提供的数据并构建了对应于CallEventRecord的标记对象:

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

我刚刚打印了标签和内容,只是为了确保它和你的一样:

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

输出:

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

所以,标签是正确的(20),内容匹配相同的结构。让我们继续。


我刚刚检查了 callEventRecord.getObject().getClass() 的值,它是一个 org.bouncycastle.asn1.BERSequence,(根据上面的 ASN.1 定义)对应于 SGSNPDPRecord。然后我遍历它的元素,只是为了检查它们的类型:

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

结果是 3 个元素,类型都是 org.bouncycastle.asn1.DERTaggedObject。然后我修改了循环来检查每一个的内容:

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;
    }
}

在循环中,您只需调用obj.getObject() 即可为每个标签获取相应的值。在我的测试中,所有元素都是 org.bouncycastle.asn1.DEROctetString 的实例,但只有上面的 ASN.1 定义,我无法判断每个字段应该如何处理。

所以,你应该用obj.getObject()得到对应的值,并根据每个字段的定义来处理这个值。