Subject: Scram as a gs2 mechanism ABNF

From: Sam Hartman <[email-masked]>
Date: Tue, 29 Jul 2008 08:12:40 -0400

Here are Nico and my notes on scram as a GSS-API mechanism.

My hope is that Chris and others will find this acceptable.

If not, there are changes to GS2 that could almost certainly make
Chris happy.

    gs2-length = 4*octet
    ctx-length = gs2-length
    wrap-length = gs2-length

    gs2-header = ctx-length wrap-length

    der-definite-length = %00-%7F / %81 octet / %82 2*octet / %83 3*octet / %84 4*octet

    gss-init-ctx-header = %60 der-definite-length "<constant encoded OID octet string here>"

    scram-c1 = gs2-header gss-init-ctx-header username "," hash-list "," nonce
	       ;; wrap-length here is 4*%00

    scram-s1 = gs2-header nonce "," hash-list "," salt "," iteration-count
	       ;; wrap-length here is 4*%00

    mac = "m=" base64 ";"
          ;; This is a GSS wrap with integrity token for SCRAM; normally
	  ;; this is all it will be, but a true SCRAM GSS mechanism may
	  ;; have sequence numbers too
    channel-binding = *(octet)

    scram-c2-ctx = nonce "," proof
    scram-c2-wrap = mac "," 4*%00 channel-binding 4*octet %00 [channel-binding] [authzid]
    scram-c2 = gs2-header scram-c2-ctx scram-c2-wrap

    scram-s2-ctx = verifier
    scram-c2-wrap = mac "," ( %08 / %00 ) 3*%00
    scram-s2 = gs2-header scram-s2-ctx scram-s2-wrap

---

From: Sam Hartman <[email-masked]>
Date: Tue, 29 Jul 2008 08:45:34 -0400

I do completely understand these are very rough.
I'd be happy to help explain things.

---

From: Chris Newman <[email-masked]>
Date: Wed, 30 Jul 2008 19:01:42 +0100

> My hope is that Chris and others will find this acceptable.

FYI, I am not likely to find this protocol acceptable, but I want to make 
sure I understand the protocol before I commit one way or the other.  At 
this point, I do not understand the "mac" rule and need to confirm my 
assumptions.

My basis for evaluating this protocol relative to the current SCRAM 
protocol is as follows:

I recognize a modest benefit in code sharing, 
deployment/implementation/interoperability if a SCRAM-GS2 mechanism and a 
SCRAM-SASL mechanism use the same bits-on-the-wire as both a GSSAPI-guru 
and a SASL-app-guy can implement in their comfort zone.  I contrast that 
with separate SCRAM-GS2 used for things like NFS that are GSSAPI only, and 
SCRAM-SASL used for things that support SASL.  In that case, there's risk 
of the GSSAPI mechanism leaking through in a SASL-based protocol (even if 
we say SHOULD NOT) and introducing interop problems -- much the way 
GSS-SPNEGO leaked into SASL.  Regardless, if SCRAM is to succeed it needs 
to be implemented in multiple frameworks (HTTP-Auth, SASL, GSSAPI, 
SSH-auth, perhaps EAP).  So the benefit of potentially eliminating one 
framework is only a modest benefit.

I contrast that with the additional complexity of implementing a pure SASL 
mechanism.  GSSAPI is not an app-level protocol; it's an OS-level protocol 
when present.  Deploying things in the OS often takes longer than deploying 
them in the app layer.  So I consider the cost of deploying the SASL 
mechanism the overriding consideration in terms of actually getting this 
mechanism deployed.

Constant binary strings are ugly, but tolerable especially if they are few 
and only a prefix or postfix.  A length is much more problematic 
(regardless of whether or not it is binary).  Each computed length is an 
opportunity for a buffer overflow implementation bug and thus makes the 
protocol itself less secure when it enters the real world.  A security 
advisory saying SCRAM is insecure due to a buffer overflow in someone's 
implementation would do harm to SCRAM deployment.

If my understanding of the number of unnecessary length fields (6) this 
change introduces is correct, then it reduces the deployment security of 
SCRAM by an amount I find unacceptable.

> If not, there are changes to GS2 that could almost certainly make

I am assuming the "4*octet" is a big-endian 32-bit unsigned integer octet 
count of part of the protocol.  I am assuming ctx-length covers the 
"context" (for each exchange respectively: scram-c1, scram-s1, 
scram-c2-ctx, scram-s2-ctx).  I am assuming wrap-length covers the 
"wrapped" portion of each exchange (respectively: 0, 0, scram-c2-wrap, 
scram-s2-wrap).

>     gss-init-ctx-header = %60 der-definite-length "<constant encoded OID

I am assuming that the "der-definite-length" is the length of the encoded 
OID only.  I presume gss-init-ctx-header will collapse to a constant octet 
string for each SCRAM mechanism name and no SCRAM implementation will be 
required to generate a DER ASN.1 length for this purpose.

>     scram-c1 = gs2-header gss-init-ctx-header username "," hash-list ","
> nonce 	       ;; wrap-length here is 4*%00
>

I do not understand where the content of the base64 comes from.  How is the 
content computed by a SCRAM implementation with no GSSAPI library present?

>     scram-c2 = gs2-header scram-c2-ctx scram-c2-wrap

I am confused about why the channel-binding may appear twice.  Can you 
explain?