Subject: Some implementor's notes

From: Greg Hudson <[email-masked]>
Date: Mon, 13 Oct 2003 13:19:19 -0400

I'm writing these notes in hopes that they will provide insight on
possible barriers to SASL's adoption.

When I created the custom Subversion protocol, I decided to use SASL
for authentication because I liked the concept and because I dislike
the properties of X.509 certificates, which (via TLS) are the only
real alternative that I know of.  I started out by implementing
ANONYMOUS and EXTERNAL myself, since those are trivial.

I figured for the real meat, I would use a library, since in an ideal
world applications have no business implementing authentication
systems.  Unfortunately, I'm finding the Cyrus library unsuitable
(I'll detail the reasons for this at the end, since it's
implementation-specific) and I can't use the gsasl library in
Subversion since it is covered by the GPL.  So, since there have been
a lot of calls for password authentication, I thought maybe I would
implement one of the shared-secret systems without stream protection;
Subversion's utility libraries already include an MD5 implementation,
so I figured I wouldn't need to introduce any complicated pieces of
code.

First, I looked into CRAM-MD5.  It doesn't authenticate the server and
it doesn't leave the window open for stream protection, but those
issues aren't critical.  I found the following sources of hidden
complexity:

  * The processing of the secret (pad to 64 bytes or digest and then
    pad to 64 bytes) is clunky and has no value in an MD5 context as
    far as I know.

  * I find it important to avoid storing passwords in clear text,
    since people often use the same password for multiple systems.  To
    accomplish this, you need an MD5 implementation which supports
    saving intermediate states.

  * The current draft mandates the use of RFC 3454, a 91-page RFC I
    don't understand and which does not look trivial to implement.
    I'm sure there are real issues with internationalized usernames
    and passwords, but the blow-up in complexity seems astounding.

Faced with these problems and a general sense of guilt at the idea of
implementing a weak system, I turned to DIGEST-MD5.  I found that
while DIGEST-MD5 is much more elegant than CRAM-MD5 in how it computes
the digests, it comes with a burdensome level of complexity which is
unrelated to its conceptual security properties.  In particular:

  * It introduces the concepts of realms, subsequent authentication,
    and authorization IDs, none of which seem to be important
    functionality for a generic shared-secret authentication scheme,
    and all of which could (I think) be handled out of band.
    Fortunately, it's not too difficult to avoid supporting those
    features.

  * Messages are composed of key-value pairs which do not obey a
    consistent syntax for the value, so parsing them is hard.  (I'm
    not convinced that Cyrus's implementation is correct, particularly
    for skipping over auth-param values.)

  * Length-counted strings would be easier to parse than quoted
    strings while remaining human-readable.

  * Implicit allowance for linear whitespace has no intrinsic value
    and renders implementations more complicated and error-prone.

  * It is not specified whether the serv-type, host, and digest-uri
    values are required.  (Cyrus treats digest-uri as required but not
    the other two, probably because it's not specified what you should
    do with an unspecified digest-uri when computing the digests.)  It
    is not made clear what security value, if any, these parameters
    have; to "detect accidental connection to the incorrect server" is
    not an important function for an authentication scheme.

  * The UTF-8 to ISO 8859-1 recoding of usernames and passwords seems
    like a very burdensome requirement to place on the protocol for
    the sake of a very implementation-specific convenience.  One can
    avoid this complexity by not supporting UTF-8, but that in itself
    is unfortunate.

Most of this complexity is there to provide wire similarity between
DIGEST-MD5 as used in SASL and in HTTP, but that's not a compelling
justification for requiring a tenfold expansion in code size over what
would be required to compute the digests and do basic parsing.

Because of this complexity, I am likely to go back to CRAM-MD5,
ignoring the RFC 3454 requirement in the current draft.  I'm not sure
what SASL can do at this point to reduce the implementation burdens,
but I have to say that I am sorely disappointed.  When one is
designing a security system, one should compromise simplicity only in
the name of security.

As promised, here are my major issues with the Cyrus SASL
implementation:

  * As I've discussed before, if you're a library invoking the SASL
    library, there's no way to ensure thread-safety while remaining
    compatible with other libraries invoking SASL.

  * The getopt interface seems to be a barrier to successfully
    documenting or internationalizing an application's configuration
    system.

  * The API does not successfully hide the complexity of the
    underlying mechanisms, such as digest-md5's realms.  (By "hide"
    here I don't mean the API shouldn't support them, but that you
    should have to go to extra effort to use them, instead of having
    to go to extra effort to ignore them.)

  * The secrets database is kept in a database format which depends on
    the build of the library.  If you go from one build to another
    (say, by upgrading versions of Red Hat) and the new build uses a
    different database, your server stops working and you get a
    cryptic error.  That seems totally unacceptable, and I wonder how
    existing users of the library are dealing with it.

  * The secrets database keeps secrets in plain text, which I find
    unacceptable due to the amount of password-sharing users do.

---

From: Greg Hudson <[email-masked]>
Date: Mon, 13 Oct 2003 13:59:53 -0400

>     for skipping over auth-param values.)

Whoops, this was based on a misreading of the syntax for auth-param (I
read it as being "auth-param=token=value" instead of just
"token=value").  So, ignore that point.

---

From: Lyndon Nerenberg <[email-masked]>
Date: Mon, 13 Oct 2003 14:41:00 -0600

>     saving intermediate states.

That's an implementation issue, and not a CRAM-MD5 problem. [More on this 
below.]

>     and passwords, but the blow-up in complexity seems astounding.

3454 is a bit verbose, but from an implementation standpoint it's really 
not that complicated. There's no getting away from stringprep. The 
alternative solution of restricting everything to US-ASCII is a 
non-starter. With the IETF heavily leaning towards stringprep for all new 
protocol work, you shouldn't have any trouble finding libraries that will 
assist with the UTF coding issues.

> ignoring the RFC 3454 requirement in the current draft.

Please don't. We have enough trouble as it is with implementations 
sending non-ASCII strings in CRAM-MD5. Without the ability to specify the 
character set in use, interoperability suffers greatly. stringprep solves 
this problem.

>     unacceptable due to the amount of password-sharing users do.

If you don't trust the OS to protect this data then your only option is 
to use a SASL mechanism that doesn't require plain text equivalent 
secrets. This is SASL mechanism specific, and not an artifact of the 
Cyrus implementation.

--lyndon

---

From: Greg Hudson <[email-masked]>
Date: Mon, 13 Oct 2003 17:11:57 -0400

> secrets. This is SASL mechanism specific, and not an artifact of the 

The issue is not how much the OS can be trusted; it's how much the owner
of the server can be trusted.  Ideally, the user should be able to
provide the secret to the server owner in such a way that the server
owner cannot reuse it with other services.

On further consideration, even if CRAM-MD5 secrets are kept in
intermediate form, that form can be reused with other CRAM-MD5 services,
so that's maybe not so useful.  However, a DIGEST-MD5 password in
intermediate form can only be used with another DIGEST-MD5 service if
the username and realm matches.  I'm not really sure what the common
practice is for realm names, but if they're commonly related to the
server hostname then the secret shouldn't be reusable in practice.

---

From: Alexey Melnikov <[email-masked]>
Date: Tue, 14 Oct 2003 11:36:47 +0100

Greg Hudson wrote:

>...
>...
I have to disappoint you, but DIGEST-MD5 requires RFC 3454 as well (at 
least it will when I publish a new revision)

>    for skipping over auth-param values.)
I suggest you try to find a case that breaks stuff. It is more 
constructive than saying that something doesn't (or may not) work.

>    and renders implementations more complicated and error-prone.
Yes. There are historical reasons why this happened.
It was a compromise between design and something that could have been 
implemented by one big vendor.
It was supposed to become a replacement for another seriously broken 
SASL mechanism NTLM.

>    values are required.
They are required to be sent, but the receiver SHOULD (but not required 
to) verify it. If the text is not clear, let me know and I will try to 
fix it.

>  (Cyrus treats digest-uri as required but not
See above.

>designing a security system, one should compromise simplicity only in
SASL has nothing to do with your problem (well, very little to do).
SASL is just a framework. If you don't like mechanisms that are 
currently available, you can write a new one and try to make it deployed.

>    documenting or internationalizing an application's configuration
Why?

>    to go to extra effort to ignore them.)
Yes, this is a bit unfortunate, but I had exactly the same problem 
trying to write a different SASL implementation.

>    the build of the library.
>
Shouldn't really. Secrets are usually stored in sasldb backend, the 
format is quite stable at this point and shouldn't change very much over 
the time.

>  If you go from one build to another
Alexey

---

From: Sam Hartman <[email-masked]>
Date: Tue, 28 Oct 2003 15:31:33 -0500

>>>>> "Greg" == Greg Hudson <[email-masked]> writes:
    Greg>   * It introduces the concepts of realms, subsequent
    Greg> authentication, and authorization IDs, none of which seem to
    Greg> be important functionality for a generic shared-secret
    Greg> authentication scheme, and all of which could (I think) be
    Greg> handled out of band.  Fortunately, it's not too difficult to
    Greg> avoid supporting those features.

I think the only point you raise that I disagree with is the idea that
authorization IDs are not important.

I can understand why an implementation might not want to use them, but
I believe they are important for protocols to support and are
something you will tend to want to add over time to an implementation.

---

From: Greg Hudson <[email-masked]>
Date: Tue, 28 Oct 2003 16:13:29 -0500

> authorization IDs are not important.

And yet, to the best of my knowledge, they are not introduced by any
mechanism other than DIGEST-MD5.  (Kerberos has multi-level principals,
but they each have different passwords, so they aren't analagous to
DIGEST-MD5 authzids.)  They are trivial to support by authenticating and
then transmitting the desired authzid.  So they should either be part of
the protocol or part of the SASL framework, but certainly not part of
SASL mechanisms.

---

From: Jeffrey Hutzelman <[email-masked]>
Date: Tue, 28 Oct 2003 16:50:44 -0500

> the protocol or part of the SASL framework, but certainly not part of

They're not introduced by this mechanism, either.  Authorization identities 
_are_ part of the SASL framework -- a client may optionally specify the 
authorization identity he wishes to assume, independent of the 
authentication identity provided by the mechanism.  It is the 
responsibility of the mechanism to transport the requested authzid, if 
there is one.

-- Jeff

---

From: Rob Siemborski <[email-masked]>
Date: Tue, 28 Oct 2003 16:48:48 -0500 (EST)

On Tue, 28 Oct 2003, Greg Hudson wrote:

> mechanism other than DIGEST-MD5.

In addition to DIGEST-MD5, the PLAIN, KERBEROS_V4, GSSAPI, SRP, and OTP
mechanisms all support authorization identifiers.  This certainly isn't
something completely new introduced by DIGEST-MD5.

> They are trivial to support by authenticating and then transmitting the
> desired authzid.  So they should either be part of the protocol or part
> of the SASL framework, but certainly not part of SASL mechanisms.

I admit that hindsight reveals that it would be nice for SASL to be able
to support authorization ids as part of the framework -- it would solve
the inconsistency introduced by CRAM-MD5.  I don't think we really want to
do this at the application layer either, since that repeats this work for
every SASL application (having application-specific constraints on the
authorization ID, however, would be fine).

However, I don't think we can abandon the current deployed infrastructure
to fix the SASL framework to allow this at this point.

-Rob

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Rob Siemborski | Andrew Systems Group * Research Systems Programmer
PGP:0x5CE32FCC | Cyert Hall 207 * [email-masked] * 412.268.7456
-----BEGIN GEEK CODE BLOCK----
Version: 3.12
GCS/IT/CM/PA d- s+: a-- C++++$ ULS++++$ P+++$ L+++(++++) E W+ N o? K-
w O- M-- V-- PS+ PE++ Y+ PGP+ t+@ 5+++ R@ tv-@ b+ DI+++ G e h r- y?
------END GEEK CODE BLOCK-----

---

From: Greg Hudson <[email-masked]>
Date: Mon, 13 Oct 2003 13:59:53 -0400

---

From: Lyndon Nerenberg <[email-masked]>
Date: Mon, 13 Oct 2003 14:41:00 -0600

--lyndon

---

From: Greg Hudson <[email-masked]>
Date: Mon, 13 Oct 2003 17:11:57 -0400

---

From: Alexey Melnikov <[email-masked]>
Date: Tue, 14 Oct 2003 11:36:47 +0100

See above.

Why?

Alexey

---

From: Sam Hartman <[email-masked]>
Date: Tue, 28 Oct 2003 15:31:33 -0500

---

From: Greg Hudson <[email-masked]>
Date: Tue, 28 Oct 2003 16:13:29 -0500

---

From: Jeffrey Hutzelman <[email-masked]>
Date: Tue, 28 Oct 2003 16:50:44 -0500

-- Jeff

---

From: Rob Siemborski <[email-masked]>
Date: Tue, 28 Oct 2003 16:48:48 -0500 (EST)

-Rob

-----BEGIN GEEK CODE BLOCK----
Version: 3.12
------END GEEK CODE BLOCK-----