[Cryptography] Is ASN.1 still the thing?
Nico Williams
nico at cryptonector.com
Sat Nov 25 22:57:54 EST 2017
On Sat, Nov 25, 2017 at 12:32:59PM +0100, Florian Weimer wrote:
> * Peter Gutmann:
> > ASN.1 has a lot of design-by-committee junk in it (the date format, for
> > example), but BER and DER are pretty clean.
ASN.1 is pretty clean, but BER/DER/CER are all crap (mainly the TLV
thing, and the poor choices made for canonicalization in DER and CER).
> What I find very hard, as someone who has never been formally trained
> in the ASN.1 arts, is going from a specification like this:
I've never been formally trained in ASN.1 either.
> Certificate ::= SEQUENCE {
> tbsCertificate TBSCertificate,
> signatureAlgorithm AlgorithmIdentifier,
> signatureValue BIT STRING }
>
> TBSCertificate ::= SEQUENCE {
> version [0] EXPLICIT Version DEFAULT v1,
> serialNumber CertificateSerialNumber,
> signature AlgorithmIdentifier,
> issuer Name,
> validity Validity,
> subject Name,
> subjectPublicKeyInfo SubjectPublicKeyInfo,
> issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
> -- If present, version MUST be v2 or v3
> subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
> -- If present, version MUST be v2 or v3
> extensions [3] EXPLICIT Extensions OPTIONAL
> -- If present, version MUST be v3
> }
>
> to the BER/DER encoding. The problem is this:
>
> version [0] EXPLICIT Version DEFAULT v1,
>
> which has a funny impact on the encoding, which turns out rather
> irregular at this point. The reset is pretty boring TLV stuff and
> easy to implement, but I never found a specification of what
> *actually* happens here. If it's described in X.690 (07/2002), I
> really don't see it.
Are you referring to the EXPLICIT keyword?
Explicit tagging -> TLV nesting. I.e., TLV' where V' is the underlying
TLV, so: TLTLV.
That's right: extra redundantly and ridiculously wasteful.
Here you get:
Tag(CONTEXT, 0) || Length(Tag(UNIVERSAL, INTEGER) ||
Length(<encoding of INTEGER 0, 1, or 2>) ||
<encoding of INTEGER 0, 1, or 2)
What was the point of using EXPLICIT tagging for that field and IMPLICIT
for the rest? I don't know, and so far I can't think of an obvious
reason.
(While we're on the subject of mistakes in x.509, it's very unnatural to
apply a signature to a subset of a PDU (in this case, tbsCertificate).
tbsCertificate should have been an OCTET STRING containing the
TBSCertificate. But whatever.)
As for where this is described... It's described in x.690, section
8.14. It's also referred to in a few places in x.680.
- x.690, 8.14:
8.14 Encoding of a tagged value
8.14.1 The encoding of a tagged value shall be derived from the complete
encoding of the corresponding data value of the type appearing
in the "TaggedType" notation (called the base encoding) as
specified in 8.14.2 and 8.14.3.
8.14.2 If implicit tagging (see ITU-T Rec. X.680 | ISO/IEC 8824-1,
30.6) was not used in the definition of the type, the encoding
shall be constructed and the contents octets shall be the
complete base encoding.
8.14.3 If implicit tagging was used in the definition of the type, then:
a) the encoding shall be constructed if the base encoding
is constructed, and shall be primitive otherwise; and
b) the contents octets shall be the same as the contents
octets of the base encoding.
This actually makes sense if you read the rest of the spec, but it's
also made more obvious by already knowing that EXPLICIT tagging means
one more layer of TLV while IMPLICIT tagging means replacing the tag
(but not the constructed/primitive bit) in the TLV encoding :(
(I'm probably coming across as defending ASN.1, but I want to make
absolutely clear that BER/DER/CER are horrible. My defense of ASN.1 is
mostly about dissuading people from reinventing that wheel _badly_. If
you want to reinvent it, please don't make the TLV mistake again.)
And here's a couple of places where x.680 talks about tagging:
- x.680, 30.5:
All application of tags is either implicit tagging or explicit
tagging. Implicit tagging indicates, for those encoding rules which
provide the option, that explicit identification of the original tag
of the "Type" in the "TaggedType" is not needed during transfer.
NOTE -- It can be useful to retain the old tag where this was
universal class, and hence unambiguously identifies the old type
without knowledge of the ASN.1 definition of the new type. Minimum
transfer octets is, however, normally achieved by the use of
IMPLICIT. An example of an encoding using IMPLICIT is given in
ITU-T Rec. X.690 | ISO/IEC 8825-1.
- x.680, E.2.12.5
Textual use of IMPLICIT with every tag is generally found only in
older specifications. BER produces a less compact representation
when explicit tagging is used than when implicit tagging is used.
PER produces the same compact encoding in both cases. With BER and
explicit tagging, there is more visibility of the underlying type
(INTEGER, REAL, BOOLEAN, etc.) in the encoded data. These guidelines
use implicit tagging in the examples whenever it is legal to do so.
This may, depending on the encoding rules, result in a compact
representation, which is highly desirable in some applications. In
other applications, compactness may be less important than, for
example, the ability to carry out strong type-checking. In the
latter case, explicit tagging can be used.
Nico
--
More information about the cryptography
mailing list