ASN.1, or how to make a binary protocol definition the easy way...

Keywords: #asn.1 #ber #mhs #protocol #tlv #x.400 #x.500

Most people aren’t familiar at all with ASN.1, and some that are, have NO clue they’re looking at ASN.1SNMP MIBs are all written as ASN.1 definitions. I’m embarking on a new project and need to define a client/server protocol. I could build my own binary protocol, which I’ve done in the past. I could also use XML, or some other text based protocol, but for what this is, it’s not really appropriate, and parsing XML is a royal bear. There’s also the issue of XML just being flat out bulky. Text based protocols have similar issues for the server trying to parse them, but they’re not as bad as XML (or heh, HTTP is!)

So for some (many) systems binary protocols are what you want. Lots of times this takes the shape of some form of basic TLV (Type, Length, Value) type protocol. This happens for many reasons, speed and simplicity being usually among them. The problem with TLV protocols is they’re hard to get to/from human readable representations. Further more developing your own binary protocol means you have to develop your own clients from the ground up, encoders, decoders, the whole enchilada. And you still have to specify your messages and such.

TLV also has the advantage of not needing to know all about all of the possible types of data in advance, or even necessarily how they’re supposed to be structured. If you receive a Type you don’t understand you can skip over ALL the data involved for that type, emit an error, disconnect, whatever you need to do that’s appropriate. In some situations you’re going to ignore it, in others you need to let someone know, in many situations an unrecognized type would indicate a lower level error occurring so your next step is to re-initiate the communications.

Enter ASN.1… I am familiar with ASN.1 only through SNMP MIBs, which, most of the time seemed to not work right, or at all. After actually getting myself acquainted with ASN.1 itself I’ve realized that this is partly to blame on ASN.1 having had multiple standards over the years and partly the fault of the individual MIB authors and the overall complexity of the SNMP MIB. Using ASN.1 itself, in your own env, should work well, provided you stick with a given revision of the spec. ASN.1 also defines BER (Basic Encoding Rules) as well as other formats for representing data encoded by a given ASN.1 definition. BER is a simple TLV protocol. BER is easily parsed by, well, anything. Embedded systems with limited memory can even deal with BER, heck, usually their protocols end up looking something like BER anyway. BER needs to be carried in something a little higher order if it’s going to be subjected to corruption or packet loss though. Something like, oh, say TCP/IP or UDP/IP (gasp!) This should come as no surprise since ASN.1 was originally designed to sit on the OSI stack above the session layer.

BER itself really only defines the ‘high level’ stuff. Sets, sequences, integers, strings, things like that. It’s up to the programmer to define the messages/data and their ordering and what they contain. In other words, to give them actual context, and meaning. ASN.1 lets you express the ordering and constraints on the data. Your application still has to apply meaning to it.

So by using ASN.1 and freely available tools to compile ASN.1 specifications into encoder/decoders I can concentrate on writing the specifics of my protocol, and not have to worry about the over the wire bits. Clients are also simpler to build because they can delegate all the lower level crap to any ASN.1 decoder/encoder. In this particular case the system will be restricted to BER, but it would be easy to change that later and allow for any of the other encoding forms as well.

Chances are, whatever platform, OS, or programming language you’re using, there’s an ASN.1 encoder/decoder. And if there isn’t? Well you can probably leverage bits of some already written one to digest the ASN.1 specification into header files or atleast definitions of message types that your application can use.