ASN.1 encoding tutorial

Introduction

Recently I in my work I had to encode an Inap (to be more precise – Sinap) content “by hand”. It’s not a rocket science however when you need to repeat this action several times it’s worth to prepare an “automatic” solution.

Input data

As an imput I have description of Furnish Charging Information in ASN.1:

FurnishChargingInformation ::= OPERATION 
   ARGUMENT FurnishChargingInformationArg 
   ERRORS {MissingParameter , 
                 TaskRefused , 
                 UnexpectedComponentSequence , 
                 UnexpectedDataValue , 
                 UnexpectedParameter } 
FurnishChargingInformationArg ::= FCIBillingChargingCharacteristics
FCIBillingChargingCharacteristics ::= OCTET STRING (SIZE (minFCIBillingChargingLen..maxFCIBillingChargingLen))

Ok, how to read it? (S)INAP message FurnishChargingInformation has an argument FurnishChargingInformationArg which is eqal to FCIBillingChargingCharacteristics. FCIBillingChargingCharacteristics is a limited size octet string.

From Sinap description document I’ve found that FCIBillingChargingCharacteristics == FCIBCC.

Now it’s time to build FCIBCC module:

-- Creator: ASN.1 Editor (http://asneditor.sourceforge.net)
-- Author: jhartman
-- Created: Sun Apr 19 21:47:18 CEST 2009
FCI-Module DEFINITIONS IMPLICIT TAGS ::= BEGIN

FCIBCC ::= SEQUENCE { 
        chargedPartyID [0] ChargedPartyID , 
        chargingInformation [1] ChargingInformation , 
        chargedPartyType [2] ChargedPartyType OPTIONAL , 
        legID [3] LegID OPTIONAL
 }

ChargedPartyID ::= OCTET STRING (SIZE(minChargedPartyIDLen.. maxChargedPartyIDLen)) 

ChargingInformation ::= CHOICE { 
        initChargingInformation [0] InitChargingInformation , 
        updateChargingInformation [1] UpdateChargingInformation 
} 

 
InitChargingInformation ::= SEQUENCE { 
        ticketControlInformation [0] TicketControlInformation OPTIONAL , 
        callTypeAndStatus [1] CallTypeAndStatus OPTIONAL , 
        billedItemList [2] BilledItemList OPTIONAL,
        inServiceSpecificData [3] INServiceSpecificData OPTIONAL,
        transparentData [4] TransparentDataFCI OPTIONAL , 
        serviceIndicator [5] ServiceIndicator OPTIONAL , 
        chargingLevel [6] ChargingLevelControl OPTIONAL , 
        zoningInPostProcessing [7] ZoningInformation OPTIONAL , 
        takeOverChargingInformation [8] BOOLEAN OPTIONAL 
} 

INServiceSpecificData ::= OCTET STRING(SIZE(1 .. 199))

TicketControlInformation ::= SEQUENCE { 
        sequenceInfo [0] SequenceInfoFCI DEFAULT firstFCI,
        ticketGenerationCondition [1] TicketGenerationCondition OPTIONAL 
}
          
SequenceInfoFCI ::= ENUMERATED { 
        firstFCI (0) , 
        subsequentFCI (1) 
} 

TicketGenerationCondition ::= ENUMERATED { 
        successfulAndUnsuccessfulCalls (0) , 
        onlySuccessfulCalls (1) , 
        onlyUnsuccessfulCalls (2) 
} 

CallTypeAndStatus ::= INTEGER (0..999) 

BilledItemList ::= SEQUENCE 
        SIZE(minBilledItemNum..maxBilledItemNum) 
OF BilledItem 

BilledItem ::= OCTET STRING (SIZE(minBilledItemLen..maxBilledItemLen)) 

TransparentDataFCI ::= OCTET STRING (SIZE(minTransparentDataFCILen..maxTransparentDataFCILen)) 

ServiceIndicator ::= Integer2

ChargingLevelControl ::= CHOICE { 
        scpChargeNumber [0] ScpChargeNumber , 
        zoningRequired [1] SSPZoningInformation , 
        freeOfCharge [2] NULL } 

ScpChargeNumber ::= OCTET STRING (SIZE(fixScpChargeNumberLen)) 

SSPZoningInformation ::= CHOICE { 
        lacAParty-BParty [0] NULL , 
        lacAParty-lacSSP [1] NULL , 
        lacAParty-DDigits [2] DDigits } 

ZoningInformation ::= CHOICE { 
        lacAParty-BParty [0] NULL , 
        lacAParty-lacSSP [1] NULL , 
        lacAParty-Ddigits [2] DDigits , 
        lacSSP-BParty [3] NULL , 
        oDigits-Bparty [4] ODigits 
}

DDigits ::= GenericDigits 

ODigits ::= GenericDigits 


-- UpdateChargingInformation

UpdateChargingInformation ::= SEQUENCE { 
        newChargedPartyType [0] ChargedPartyType OPTIONAL , 
        newChargedPartyID [1] ChargedPartyID OPTIONAL , 
        addBilledItemList [2] BilledItemList OPTIONAL 
} 

ChargedPartyType ::= OCTET STRING (SIZE(fixChargedPartyTypeLen))

LegID ::= CHOICE { 
        sendingSideID [0] LegType -- used in operations sent from SCF to SSF -- , 
        receivingSideID [1] LegType -- used in operations sent from SSF to SCF -- } 

LegType ::= OCTET STRING (SIZE (fixLegTypeLen)) 

Integer2 ::= INTEGER (0..65535) 

GenericDigits ::= OCTET STRING (SIZE (minGenericDigitsLen..maxGenericDigitsLen))

-- constrains

minBilledItemLen INTEGER ::= 1 
maxBilledItemLen INTEGER ::= 3 
minBilledItemNum INTEGER ::= 1 
maxBilledItemNum INTEGER ::= 3 
minChargedPartyIDLen INTEGER ::= 1 
maxChargedPartyIDLen INTEGER ::= 16 
fixChargedPartyTypeLen INTEGER ::= 1 
minTransparentDataFCILen INTEGER ::= 1 
maxTransparentDataFCILen INTEGER ::= 20

fixLegTypeLen INTEGER ::= 1 

minGenericDigitsLen INTEGER ::= 1 
maxGenericDigitsLen INTEGER ::= 26 

fixScpChargeNumberLen INTEGER ::= 2 

END

(save whole module as FCI-Module.asn)

What’s this? It’s a top-down definition of all elements needed to describe FCIBCC.

Building the tool

We have prepared an abstract description of FCIBCC. “Abstract” means – has no mapping to real bits and bytes yet. However, we know that in INAP protocol bytes are encoded according to BER notation. Let’s take a pen, piece of paper and spend some time to create hex output we’re looking for. Wait, this is not the way we would like to go. We’re looking for a tool 🙂

First – let’s get an ASN.1 compiler. Usually, commercial tool costs a lot of $$$. Really LOT. Lucky – I’ve found one freeware. Look for open source ANS.1 compiler. Download it and build on your platform.

Next, compile FCI-Module.asn. It should compile without errors:

Jarek-Hartmans-Mac:asn1-2 jhartman$ asn1c FCI-Module.asn 
Compiled FCIBCC.c (contents unchanged)
Compiled FCIBCC.h (contents unchanged)
Compiled ChargedPartyID.c (contents unchanged)
Compiled ChargedPartyID.h (contents unchanged)
Compiled ChargingInformation.c (contents unchanged)
Compiled ChargingInformation.h (contents unchanged)
Compiled InitChargingInformation.c (contents unchanged)
Compiled InitChargingInformation.h (contents unchanged)
Compiled INServiceSpecificData.c (contents unchanged)
Compiled INServiceSpecificData.h (contents unchanged)
Compiled TicketControlInformation.c (contents unchanged)
Compiled TicketControlInformation.h (contents unchanged)
Compiled SequenceInfoFCI.c (contents unchanged)
Compiled SequenceInfoFCI.h (contents unchanged)
Compiled TicketGenerationCondition.c (contents unchanged)
Compiled TicketGenerationCondition.h (contents unchanged)
Compiled CallTypeAndStatus.c (contents unchanged)
.
.
.

An output we got a source file for our tool. Now it’s time to build the tool:

Jarek-Hartmans-Mac:asn1-2 jhartman$ cc -DPDU=FCIBCC -I. *.c -o FCI
converter-sample.c: In function 'add_bytes_to_buffer':
converter-sample.c:485: warning: pointer targets in assignment differ in signedness
converter-sample.c: In function 'data_decode_from_file':
converter-sample.c:539: warning: pointer targets in assignment differ in signedness
converter-sample.c:577: warning: pointer targets in assignment differ in signedness
converter-sample.c:580: warning: pointer targets in assignment differ in signedness

(we got several warnings but just ignore them)

Success!

Using the tool

Our goal is to prepare flow of hex numbers that’s corresponding to following XER data:

<FCIBCC>
    <chargedPartyID>21 43</chargedPartyID>
    <chargingInformation>
        <initChargingInformation>
            <ticketControlInformation>
                <sequenceInfo><subsequentFCI/></sequenceInfo>
                <ticketGenerationCondition><onlySuccessfulCalls/></ticketGenerationCondition>
            </ticketControlInformation>
        </initChargingInformation>
    </chargingInformation>
    <legID>
        <sendingSideID>01</sendingSideID>
    </legID>
</FCIBCC>

(save it as FCI.xer)

If you compare XER data with FCI-Module.asn you can easily recognise what’s going on. XER encoding is very handy human-readable format for all this ASN.1 stuff. Let’s convert it to real BER (to be more precise – DER):

Jarek-Hartmans-Mac:asn1-2 jhartman$ ./FCI -ixer -oder FCI-TP-FPH.xer | hexdump 
0000000 30 26 80 09 54 65 73 74 5f 65 77 73 64 a1 19 a0
0000010 17 a0 03 80 01 00 81 02 03 e7 a2 05 04 03 01 00
0000020 00 84 02 80 00 85 01 01 

When you copy these hex numbers into your IN application and put FCI message on the wire you should get something similar to:

FCI

Can you recognize highlighted numbers? Yes, yes – they are exactly the same as we got from our FCI-converter.

Let’s assume now we would like to convert hex (or more precise – BER encoded) FurnishChargingInformationArg to human readable XML.

Save highlighted element. In Wireshark I’m using right mouse button -> Copy -> Hex (Hex stream). Save it to txt file:

Jarek-Hartmans-Mac:asn1-2 jhartman$ cat FCI-from-wireshark.txt 
301580022143a10aa008a006800101810101a303800101

Now convert hex-text file into real binary:

Jarek-Hartmans-Mac:asn1-2 jhartman$ xxd -r -p FCI-from-wireshark.txt > FCI-from-wireshark.ber

Now we can convert BER stream into human-readable format using our hand-made tool:

Jarek-Hartmans-Mac:asn1-2 jhartman$ ./FCI FCI-from-wireshark.ber 
<FCIBCC>
    <chargedPartyID>21 43</chargedPartyID>
    <chargingInformation>
        <initChargingInformation>
            <ticketControlInformation>
                <sequenceInfo><subsequentFCI/></sequenceInfo>
                <ticketGenerationCondition><onlySuccessfulCalls/></ticketGenerationCondition>
            </ticketControlInformation>
        </initChargingInformation>
    </chargingInformation>
    <legID>
        <sendingSideID>01</sendingSideID>
    </legID>
</FCIBCC>

Pretty cool, heh?

References

 

ASN.1 encoding tutorial

Leave a Reply

Your email address will not be published. Required fields are marked *