ASN.1 across revisions

Paul Long Plong at SMITHMICRO.COM
Sun Jun 28 20:12:14 EDT 1998

On Wed, 24 Jun 1998, Pekka Pessi wrote:

>    The current H.225.0 algorithm for calculating the ICV does not work well
>    with the PER extension mechanism.


>    The above algorithm (AFAIK I have understood it correctly) assumes that
>    the sender and receiver can encode the PDU exactly in the same way. It is
>    a reasonable assumption, as PER produces only one possible (canonical)
>    encoding for given PDU.

PER is not inherently canonical.  To get canonical behavior you have to
either do as this set of standards have been doing and stay away from
types REAL and SET OF, or you have to use Canonical PER Aligned or
Canonical PER Unaligned.

> However, there is a serious problem: the
>    canonical representation changes if the ASN.1 SEQUENCE type is extended
>    later.


>    When encoding this, the length of extension bitfield is 2.  However,
>    recipient B is using extended version of Foo like this:
>       Foo ::= SEQUENCE
>       {
>            bar                 INTEGER (0..127),
>            ...,
>            baz                 INTEGER (0..255) OPTIONAL,
>            integrityCheckValue ICV OPTIONAL,
>            importantExtension  SomeType OPTIONAL
>       }

A lot of research has gone into how to most effectively create ICV's
by the designers of the Secure Electronic Payment protocol (SET),
e-check protocol and others.  That's why in SET you see the likes of:

    UnsignedCertificate ::= SEQUENCE {
       version               [0] CertificateVersion,
       serialNumber          CertificateSerialNumber,
       signature             AlgorithmIdentifier {{SignatureAlgorithms}},
       issuer                Name,
       validity              Validity,
       subject               Name,
       subjectPublicKeyInfo  SubjectPublicKeyInfo{{SupportedAlgorithms}},
       issuerUniqueID        [1] IMPLICIT UniqueIdentifier OPTIONAL,
       subjectUniqueID       [2] IMPLICIT UniqueIdentifier OPTIONAL,
       extensions            [3] Extensions     -- Required for SET usage

    -- Compute the encrypted hash of this value if issuing a certificate,
    -- or recompute the issuer's signature on this value if validating a
    -- certificate.
    EncodedCertificate ::= TYPE-IDENTIFIER.&Type (UnsignedCertificate)

    Certificate::=   SIGNED {
    } ( CONSTRAINED BY { -- Verify Or Sign Certificate -- } )

    SIGNED { ToBeSigned } ::= SEQUENCE {
       toBeSigned  ToBeSigned,
       algorithm   AlgorithmIdentifier {{SignatureAlgorithms}},
       signature   BIT STRING

The key thing to notice is that they DO NOT attempt to sign the unencoded
certificate (i.e., UnsignedCertficate).  The actual signing occurs on an
open type which has been constrained to carry the value of the particular
type that is to be signed (TYPE-IDENTIFIER.&Type (UnsignedCertificate)).
In so doing, a) they clearly identify that the type should be encoded
independently of the ICV, b) they avoid having to do a re-encode of the
data after the CRV has been calculated, c) the type to which the ICV is to
be applied can be extended with no problem, and d) they prepared
themselves for the possible use of PER by utilizing an open type to carry
the value to be signed - something that is *crucial* to signing
PER-encoded data.

> Problems with Non-OPTIONAL Extensions
>    Another problem with some ASN.1 compilers is inclusion of non-OPTIONAL
>    extensions. Let us assume that software C uses following ASN.1 definition
>    for Foo:
>       Foo ::= SEQUENCE
>       {
>            bar                 INTEGER (0..127),
>            ...,
>            baz                 INTEGER (0..255) OPTIONAL,
>            integrityCheckValue ICV OPTIONAL,
>            importantExtension  SomeType OPTIONAL,
>            criticalExtension   OtherType
>       }
>    There are two kinds of problems with an extension like criticalExtension.
>    First, the encoder may try to ensure that all encoded PDUs conform to the
>    specification and signal an error when a PDU without criticalExtension is
>    encoded.

That's the correct behavior only if you are originating a message.
Encoders should not complain about criticalExtension being absent
if they are not originating the message.

>    Another problem is that the intermediate representation produced
>    by the ASN.1 compiler may not provide means for application to express
>    that criticalExtension is not present. (In other words, the produced
>    structure usually contains a flag telling whether an optional field is
>    present or not. Such flags are not included when the field is not
>    optional.)

It is an error for encoders not to encode extension additions that are
mandatory but missing if such extension additions do not occur within an
extension addition group and if no other extension addition values follow
the missing but mandatory extension. (I don't believe H.225 employs
extension addition groups (i.e., the "[[" and "]]" notation.))  This is
indicated in X.680:1997 clause 7.1 (X.680:1994 Amd.1 clause 6.1) which
unconditionally mandates that it be possible for decoded components that
are defined to both the sender and receiver be re-encodable by the

>    The presense or absence of the OPTIONAL flag in an extension does not
>    change the PER encoding of the SEQUENCE. In order to avoid previously
>    mentioned problems, application may use a version of ASN.1 notation that
>    has extra OPTIONAL keyword after each extension.

Neat!  A nice and simple solution for use with such compilers.

> Solution 1: Clarification to the PER Encoding Process
>    The text in PER document (X.691, 1994) is somewhat ambiguous how many
>    bits should be included in the extension present bitfield of SEQUENCE. To
>    quote verbatim: "Let the number of extension additions in the type being

Note that it says the *type* being encoded, not the value.  That's
distinct from the value.

>    encoded be "n", then a bit-field with "n" bits shall be produced for
>    addition to the field-list." (Is the "type being encoded" the abstract
>    syntax or an actual value like { bar 1, baz 2 }?)  However, the 0 bits at
>    the end of extension present bitfield can be left out without changing
>    the resulting semantics: the corresponding extensions are not present.

It is true that they can be left out without changing the semantics, but
this is not what PER mandates (It should have mandated what you suggest,
but hindsight is 20-20.)  Unless everyone encodes according to PER its
canonical nature will be lost.

>    As a result, the PER encoding does not change after a new extension
>    is added to the ASN.1 specification.
>    This solution, while leaving H.225.0 v2 protocol as it is, requires
>    however changes to some existing ASN.1 compilers, and in a pessimal case,
>    to the X.691 standard text, too.

Yes, this would work, but as you point out, it requires that PER be

> Solution 2: Hack
>    The receiving application does not decode and the re-encode the PDU, but
>    rather removes the ICV from the encoded PDU. In practice, this requires that
>    application can identify PER-encoded fields within the PDU and it can
>    regenerate them, i.e.  it has effectively the same functionality as a PER
>    encoder/decoder.
> Solution 3: Calculating ICV Differently
>    The following algorithm for generating and checking the ICV makes it
>    possible to avoid all the previously mentioned problems. The problems are
>    avoided by breaking the protocol layering, the application changes directly
>    the PER-encoded PDU:
>    integrityCheckValue - provides improved message integrity/message
>         authentication of the RAS messages. The cryptographically based
>         integrity check value is computed by the sender applying a
>         negotiated integrity algorithm and the secret key upon the entire
>         message. Prior to integrityCheckValue computation an ICV with a
>         previously agreed magic value (or key when using MDC) will be
>         inserted to this field. The magic value will contain same
>         algorithmOID and exactly as many bits in the icv BIT STRING as the
>         computed value. After computation, the sender replaces the magic
>         value with the computed integrity check value and transmits
>         message. The receiver decodes message, replaces the received
>         integrity value with the magic value, calculates the ICV and
>         compares it with the received value.
>    NOTE: The sender or receiver can encode the ICV separately and replace
>         it directly within the encoded PDU, when the magic ICV and computed
>         ICV have exactly the same length.  When replacing ICV value within
>         an encoded PDU, re-encoding the whole PDU can be avoided.

I don't like this too much because of the possibility, though low,
of the data containing the magic ICV value.  Still I prefer it to
solutions 1 and 2.

> Solution 4:
>  Fourth alternative is to treat encoded RasMessage as octet string. IVC
>  can be calculated over that octet string and appended to the PDU on
>  separate layer.  E.g., RAS PDU could be defined as follows:
>      RasMessage ::= CHOICE {
>         -- all previous RasMessage CHOICEs are here
>         authenticatedRasMessage SEQUENCE {
>            plainRasMessage OCTET STRING,
>            ivc             IVC,
>            ...
>         }
>      }

This is effectively what is done in SET and other security-conscious
protocols, though they typically use open type instead of octet string.

Alternate Solution 1:

To do exactly as is done in SET, you would define RasMessage without an
ICV, and define a container, AuthenticatedRasMessage, say, that carries
the encoded RasMessage as an open type value (i.e., octet-aligned, and
padded with 0-bits at the end to ensure that it is an integral multiple of
8 bits) followed by the ICV value. In other words:

    AuthenticatedRasMessage ::= SEQUENCE {
        plainRasMessage    TYPE-IDENTIFIER.&Type (RasMessage),
        ivc                IVC

Using this approach, the RasMessage (which would be defined without an
ICV) would be encoded, then the ICV would be calculated using the encoded
RasMessage, then AuthenticatedRasMessage would be encoded.  This approach
is efficient because RasMessage does not have to be encoded without
the ICV value then re-encoded with it, nor does it require that the
encoded value be tinkered with in any way.

This technique is good only if backward compatibility is not an issue
(i.e., if you don't already have a deployed version of H.225), for the
open type carries a length component than an ordinary encoded RasMessage
does not have.

Alternate Solution 2:

If backward compatibility is an issue then Solution 4 above is a better
alternative, though I would change it to:

    RasMessage ::= CHOICE {
        -- all previous RasMessage CHOICEs are here
        authenticatedRasMessage  AuthenticatedRasMessage

Open type and octet string produce identical encodings, but I have a
preference for the open type notation because it allows you to clearly
identify what the value is - in this case an encoded RasMessage, and
because it can simplify implementations that may not have a need to
authenticate the RasMessage upon decoding (e.g., line monitors.)

I am not intimate with H.225, so I don't know for sure of Solution 4
or this minor variation is backward compatible.  It is if the ICV was
just introduced, else I don't think it is.

Bancroft Scott                                Toll Free    :1-888-OSS-ASN1
Open Systems Solutions, Inc.                  International:1-609-987-9073
baos at                                  Tech Support :1-732-249-5107                            Fax          :1-732-249-4636

More information about the sg16-avd mailing list