For example, here's a sample ASN.1 definition from the LDAP protocol, using the ASN.1 primitive OCTET STRING, and the constructor SEQUENCE. The placement of ::= symbols, comments, and braces are all defined by the ASN.1 grammer.
LDAPString ::= OCTET STRING AttributeDescription ::= LDAPString AttributeValueAssertion ::= SEQUENCE { attributeDesc AttributeDescription, assertionValue AssertionValue } AssertionValue ::= OCTET STRING
RFC 2251, the LDAP standard, specifies that BER should be used to encode the ASN.1 structures used in LDAP. So, let's encode this AttributeValueAssertion:
{attributeDesc "cn", assertationValue "www.freesoft.org"}
We follow the BER rules. A SEQUENCE is encoded with a tag byte of 30H, followed by the length of the SEQUENCE, followed by each of the component parts. An OCTET STRING is encoded with a tag byte of 05H, followed by the length of the string, followed by its value. Lengths less than 128 bytes can be encoded directly in one byte, so the final BER encoding is:
One of the advantages of ASN.1 is that, due to its well-defined syntax, automated tools can be constructed to compile ASN.1 definitions into subroutines that can encode and decode ASN.1 messages, simplifying the design of programs implementing ASN.1-based protocols. One of ASN.1's perceived disadvantages is the relative inefficiency of its encodings, and the additional computational overhead required to convert back and forth from them.