
Finally. We're almost at parity for the template compiler. Now we have a build option to use templating: `./configure --enable-asn1-templating` Tests fail if you build `rfc2459.asn1` with `--template`. TBD: Figure out what differences remain between the two compilers, and fix the templating compiler accordingly, adding tests along the way. Making IMPLICIT tags work in the templating compiler turned out to be a simple fix: don't attempt to do anything clever about IMPLICIT tags in the template generator in the compiler other than denoting them -- instead leave all the smarts about IMPLICIT tags to the interpreter. This might be a very slight pessimization, but also a great simplification. The result is very elegant: when the interpreter finds an IMPLICIT tag it then recurses to find the template for the body of the type so-tagged, and evaluates that. Much more elegant than the code generated by the non-template compiler, not least for not needing any additional temporary memory allocation. With this we finally have parity in basic testing of the template compiler. Indeed, for IMPLICIT tags the template compiler and interpreter might even be better because they support IMPLICIT tags with BER lengths, whereas the non-template compiler doesn't (mostly because `der_replace_tag()` needs to be changed to support it. And, of course, the template compiler is simply superior in that it produces smaller code and is *much* easier to work with because the functions to interpret templates are small and simple. Which means we can add more functions to deal with other encoding rules fairly trivially. It should be possible to add all of these with very little work, almost all of it localized to `lib/asn1/template.c`: - PER Packed Encoding Rules [X.691] - XER XML Encoding Rules [X.693] - OER Octet Encoding Rules [X.696] (intended to replace PER) - JER JSON Encoding Rules [X.697] (doubles as visual representation) - GSER Generic String E.R.s [RFC3641] (a visual representation) - XDR External Data Repr. [STD67][RFC4506] (XDR is *not* an ASN.1 encoding rules specification, but it's a *lot* like PER/OER but with 4-octet alignment, and is specified for the syntax equivalent (XDR) of only a subset of ASN.1 syntax and semantics.) All we'd have to do is add variants of `_asn1_{length,encode,decode}()` for each set of rules, then generate per-type stub functions that call them (as we already do for DER). We could then have an encoding rule transliteration program that takes a `TypeName` and some representation of a value encoded by some encoding rules, and outputs the same thing encoded by a different set of rules. This would double as a pretty-printer and parser if we do add support for JER and/or GSER. It would find the template for the given type using `dlsym()` against some shared object (possibly `libasn1` itself). Whereas generating source code for C (or whatever language) for additional ERs requires much more work. Plus, templates are much smaller, and the interpreter is tiny, which yields much smaller text and much smaller CPU icache/dcache footprint, which yields better performance in many cases. As well, the template system should be much easier to port to other languages. Though in the cases of, e.g., Rust, it would require use of `unsafe` in the interpreter, so in fact the inverse might be true: that it's easier to generate safe Rust code than to implement a template interpreter in Rust. Similarly for Haskell, OCAML, etc. But wherever the template interpreter is easy to implement, it's a huge win. Note that implementing OER and PER using the templates as they are currently would be a bit of a challenge, as the interpreter would have to first do a pass of each SEQUENCE/SET to determine the size and layout of the OER/PER sequence/set preamble by counting the number of OPTIONAL/DEFAULT members, BOOLEAN members, and extensibility markers with extensions present. We could always generate more entries to encode precomputed preamble metadata. We would also need to add a template entry type for extensibility markers, which currently we do not.
205 lines
9.3 KiB
Groff
205 lines
9.3 KiB
Groff
-- $Id$
|
|
|
|
-- Version 2 of the kx509 protocol is documented in RFC6717.
|
|
--
|
|
-- Our version here has extensions without changing the version number on the
|
|
-- wire.
|
|
|
|
KX509 DEFINITIONS ::= BEGIN
|
|
IMPORTS Extensions FROM rfc2459
|
|
KerberosTime FROM krb5;
|
|
|
|
KX509-ERROR-CODE ::= INTEGER {
|
|
KX509-STATUS-GOOD(0),
|
|
KX509-STATUS-CLIENT-BAD(1),
|
|
KX509-STATUS-CLIENT-FIX(2),
|
|
KX509-STATUS-CLIENT-TEMP(3),
|
|
KX509-STATUS-SERVER-BAD(4),
|
|
KX509-STATUS-SERVER-TEMP(5),
|
|
-- 6 is used internally in the umich client, avoid that
|
|
KX509-STATUS-SERVER-KEY(7),
|
|
-- CSR use negotiation:
|
|
KX509-STATUS-CLIENT-USE-CSR(8)
|
|
-- Let us reserve 1000+ for Kebreros protocol wire error codes -Nico
|
|
}
|
|
|
|
-- Originally kx509 requests carried only a public key. We'd like to have
|
|
-- proof of possession, and the ability to carry additional options, both, in
|
|
-- cleartext and otherwise.
|
|
--
|
|
-- We'll use a CSR for proof of posession and desired certificate extensions.
|
|
--
|
|
-- We'll also provide a non-CSR-based method of conveying desired certificate
|
|
-- extensions. The reason for this is simply that we may want to have a [e.g.,
|
|
-- RESTful HTTP] proxy for the kx509 service, and we want clients to be able to
|
|
-- be as simple as possible -cargo-culted even- with support for attributes
|
|
-- (desired certificate extensions) as parameters outside the CSR that the
|
|
-- proxy can encode without having the private key for the CSR (naturally).
|
|
--
|
|
-- I.e., ultimately we'll have a REST endpoint, /kx509, say, with query
|
|
-- parameters like:
|
|
--
|
|
-- - csr=<base64-encoding-of-DER-encoded-CSR>
|
|
-- - eku=<OID>
|
|
-- - ku=<key-usage-flag-name>
|
|
-- - rfc822Name=<URL-escaped-email-address>
|
|
-- - xMPPName=<URL-escaped-jabber-address>
|
|
-- - dNSName=<URL-escaped-FQDN>
|
|
-- - dNSSrv=<URL-escaped-_service.FQDN>
|
|
-- - registeredID=<OID>
|
|
-- - principalName=<URL-escaped-RFC1964-format-Kerberos-Principal-Name>
|
|
--
|
|
-- with exactly one CSR and zero, one, or more of the other parameters.
|
|
--
|
|
-- We'll even have a way to convey a bearer token from the REST proxy so that
|
|
-- we may have a way to get PKIX credentials using bearer tokens. And then,
|
|
-- using PKINIT, we may have a way to get Kerberos credentials using bearer
|
|
-- tokens.
|
|
--
|
|
-- To do this we define a Kx509CSRPlus that we can use in the `pk-key' field of
|
|
-- Kx509Request (see below):
|
|
Kx509CSRPlus ::= [APPLICATION 35] SEQUENCE {
|
|
-- PKCS#10, DER-encoded CSR, with or without meaningful attributes
|
|
csr OCTET STRING,
|
|
-- Desired certificate Extensions such as KeyUsage, ExtKeyUsage, or
|
|
-- subjectAlternativeName (SAN)
|
|
exts Extensions OPTIONAL,
|
|
-- Desired certificate lifetime
|
|
req-life KerberosTime OPTIONAL,
|
|
...
|
|
}
|
|
|
|
-- Version 2
|
|
Kx509Request ::= SEQUENCE {
|
|
authenticator OCTET STRING,
|
|
pk-hash OCTET STRING, -- HMAC(ticket_session_key, pk-key)
|
|
pk-key OCTET STRING -- one of:
|
|
-- - the public key, DER-encoded (RSA, basically)
|
|
-- - a Kx509CSRPlus
|
|
}
|
|
|
|
-- Kx509ErrorCode is a Heimdal-specific enhancement with no change on the wire,
|
|
-- and really only just so the error-code field below can fit on one line.
|
|
Kx509ErrorCode ::= INTEGER (-2147483648..2147483647)
|
|
|
|
Kx509Response ::= SEQUENCE {
|
|
error-code[0] Kx509ErrorCode DEFAULT 0,
|
|
hash[1] OCTET STRING OPTIONAL, -- HMAC(session_key, ...)
|
|
certificate[2] OCTET STRING OPTIONAL, -- DER-encoded Certificate
|
|
-- if client sent raw RSA SPK
|
|
-- or DER-encoded Certificates
|
|
-- (i.e., SEQ. OF Certificate)
|
|
-- if client used a
|
|
-- Kx509CSRPlus
|
|
e-text[3] VisibleString OPTIONAL
|
|
}
|
|
|
|
-- Offset for Kerberos protocol errors when error-code set to one:
|
|
kx509-krb5-error-base INTEGER ::= 1000
|
|
|
|
-- RFC6717 says this about error codes:
|
|
--
|
|
-- +------------+-----------------------------+------------------------+
|
|
-- | error-code | Condition | Example |
|
|
-- +------------+-----------------------------+------------------------+
|
|
-- | 1 | Permanent problem with | Incompatible version |
|
|
-- | | client request | |
|
|
-- | 2 | Solvable problem with | Expired Kerberos |
|
|
-- | | client request | credentials |
|
|
-- | 3 | Temporary problem with | Packet loss |
|
|
-- | | client request | |
|
|
-- | 4 | Permanent problem with the | Internal |
|
|
-- | | server | misconfiguration |
|
|
-- | 5 | Temporary problem with the | Server overloaded |
|
|
-- | | server | |
|
|
-- +------------+-----------------------------+------------------------+
|
|
--
|
|
-- Looking at UMich CITI's kca (server-side of kx509) implementation, it always
|
|
-- sends 0 as the status code, and the UMich CITI kx509 client never checks it.
|
|
-- All of these error codes are local only in the UMich CITI implementation.
|
|
--
|
|
-- Meanwhile, Heimdal used to never send error responses at all.
|
|
--
|
|
-- As a result we can use whatever error codes we want. We'll send Kerberos
|
|
-- protocol errors + 1000. And we'll never use RFC6717 error codes at all.
|
|
--
|
|
-- Looking at umich source...
|
|
--
|
|
-- #define KX509_STATUS_GOOD 0 /* No problems handling client request */
|
|
-- #define KX509_STATUS_CLNT_BAD 1 /* Client-side permanent problem */
|
|
-- /* ex. version incompatible */
|
|
-- #define KX509_STATUS_CLNT_FIX 2 /* Client-side solvable problem */
|
|
-- /* ex. re-authenticate */
|
|
-- #define KX509_STATUS_CLNT_TMP 3 /* Client-side temporary problem */
|
|
-- /* ex. packet loss */
|
|
-- #define KX509_STATUS_SRVR_BAD 4 /* Server-side permanent problem */
|
|
-- /* ex. server broken */
|
|
-- #define KX509_STATUS_SRVR_TMP 5 /* Server-side temporary problem */
|
|
-- /* ex. server overloaded */
|
|
-- #define KX509_STATUS_SRVR_CANT_CLNT_VERS 6 /* Server-side doesn't handle */
|
|
-- /* existence of client_version */
|
|
-- /* field in KX509_REQUEST */
|
|
--
|
|
-- The umich server uses these errors in these situations:
|
|
--
|
|
-- - KX509_STATUS_SRVR_TMP is for:
|
|
-- - request decode errors
|
|
-- - krb5_is_ap_req() errors
|
|
-- - wrong Kerberos protocol vno in AP-REQ
|
|
-- - some ENOMEMs
|
|
-- - UDP read errors (??)
|
|
-- - LDAP issues (they use LDAP to map realm-chopped user princ names to
|
|
-- full names)
|
|
-- - pk decode errors
|
|
-- - KX509_STATUS_CLNT_TMP is for:
|
|
-- - HMAC mismatch
|
|
-- - some ENOMEMs
|
|
-- - failure to accept AP-REQ
|
|
-- - failure to unparse princ names from AP-REQ's Ticket
|
|
-- - KX509_STATUS_SRVR_BAD is for:
|
|
-- - configuration issues (missing issuer creds)
|
|
-- - serial number transaction issues (we should randomize)
|
|
-- - subjectName construction issues
|
|
-- - certificate construction issues (ENOMEM, say)
|
|
-- - failure to authenticate (never happens, since KX509_STATUS_CLNT_TMP is
|
|
-- used earlier when krb5_rd_req() fails)
|
|
-- - KX509_STATUS_CLNT_FIX is for:
|
|
-- - more than one component client principals
|
|
-- - client princ name component zero string length shorter than 3 or
|
|
-- longer than 8 (WTF)
|
|
-- - other policy issues
|
|
-- - KX509_STATUS_CLNT_BAD
|
|
-- - wrong protocol version number (version_2_0)
|
|
|
|
-- Possible new version designs:
|
|
--
|
|
-- - keep the protocol the same but use a CSR instead of a raw RSA public key
|
|
-- - on the server try decoding first a CSR, then a raw RSA public key
|
|
--
|
|
-- - keep the protocol the same but use either a CSR or a self-signed cert
|
|
-- - on the server try decoding first a Certificate, then a CSR, then a raw
|
|
-- RSA public key
|
|
--
|
|
-- CSRs are a pain to deal with. Self-signed certificates can act as a
|
|
-- CSR of a sort. Use notBefore == 1970-01-01T00:00:00Z and an EKU
|
|
-- denoting "this certificate is really a much-easier-to-work-with CSR
|
|
-- alternative".
|
|
--
|
|
-- - keep the protocol similar, but use the checksum field of the
|
|
-- Authenticator to authenticate the request data; use a KRB-PRIV for the
|
|
-- reply
|
|
--
|
|
-- - extend the KDC/AS/TGS protocols to support certificate issuance, either
|
|
-- at the same time as ticket acquisition, or as an alternative
|
|
-- - send a CSR as a authz-data element
|
|
-- - expect an EncryptedData with the issued Certificate inside as the
|
|
-- Ticket in the result (again, ugly hack)
|
|
-- - or maybe just add new messages, but, the thing is that the existing
|
|
-- "AP-REP + stuff" kx509 protocol is a fine design pattern, there's no
|
|
-- need to radically change it, just slightly.
|
|
--
|
|
-- The main benefit of using an extension to the KDC/AS/TGS protocols is that
|
|
-- we could then use FAST for confidentiality protection.
|
|
|
|
END
|