




Network Working Group                                          C. Newman
Internet Draft: SCRAM-MD5 SASL Mechanism                        Innosoft
Document: draft-newman-auth-scram-03.txt                      March 1998
                                                   Expires in six months


       Salted Challenge Response Authentication Mechanism (SCRAM)


Status of this memo

     This document is an Internet-Draft.  Internet-Drafts are working
     documents of the Internet Engineering Task Force (IETF), its areas,
     and its working groups.  Note that other groups may also distribute
     working documents as Internet-Drafts.

     Internet-Drafts are draft documents valid for a maximum of six
     months and may be updated, replaced, or obsoleted by other
     documents at any time.  It is inappropriate to use Internet-Drafts
     as reference material or to cite them other than as "work in
     progress."

     To view the entire list of current Internet-Drafts, please check
     the "1id-abstracts.txt" listing contained in the Internet-Drafts
     Shadow Directories on ftp.is.co.za (Africa), ftp.nordu.net
     (Europe), munnari.oz.au (Pacific Rim), ds.internic.net (US East
     Coast), or ftp.isi.edu (US West Coast).


Abstract

     SCRAM is a simple passphrase-based SASL [SASL] authentication
     mechanism suitable for a wide variety of usage scenarios.  It
     combines good properties of CRAM-MD5 [CRAM-MD5] and OTP [OTP], adds
     some management features and some protection from active attacks
     without a significant increase in complexity.  SCRAM is intended
     for use with services which need a simple, fast and flexible
     authentication mechanism.

     [NOTE: Public discussion of this mechanism may take place on the
     ietf-sasl@imc.org mailing list with a subscription address of
     ietf-sasl-request@imc.org.  Private comments may be sent to the
     author].


1. How to Read This Document

     This document has information for several different audiences.



Newman                                                          [Page 1]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


     Section 2 provides an introduction to SCRAM.  Sections 3-6 and 9
     are intended for implementors.  Section 7 is intended for system
     administrators.  Sections 7-10 are intended for security
     evaluation.

     The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT" and "MAY"
     in this document are to be interpreted as defined in "Key words for
     use in RFCs to Indicate Requirement Levels" [KEYWORDS].


2. Introduction

     This section describes the design goals, an overview of how SCRAM
     operates and the intended use of SCRAM in comparison to OTP.


2.1. Design Goals

     The perfect authentication mechanism would be simple, fast, strong,
     use publicly available source code and be backwards compatible with
     deployed back-end authentication databases.  It is impossible to
     achieve all these goals so tradeoffs must be made.  SCRAM has
     simplicity, speed and protection from passive and active attacks on
     the connection (with the exception of dictionary attacks) as
     primary design goals.  It has managability, backwards compatibility
     with CRAM-MD5 intermediate HMAC state verifiers, some protection
     from a compromised authentication database and publicly
     distributable source code as secondary design goals.

     SCRAM has the following characteristics:

     o  It is a simple passphrase-based mechanism which does not require
        complicated infrastructures or public key technology.  The
        majority of the source code necessary to implement SCRAM is
        included in the MD5 specification [MD5] and Appendices B and C
        of this specification.

     o  It does not require plain-text-equivalent verifiers on the
        server, so it improves network security over traditional
        plain-text password systems without eliminating security of the
        server authentication database.

     o  It supports proxy authentication by including an authorization
        identity (user to login as) separate from the authentication
        identity (server authentication database entry to use).

     o  It supports mutual authentication.




Newman                                                          [Page 2]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


     o  It supports a limited service trust management model.  This
        means a centralized authentication server could restrict the
        services offered by application servers.

     o  It is backwards-compatible with CRAM-MD5 server authentication
        databases.

     o  It includes an optional SASL integrity protection layer for
        lightweight protection from many active attacks.


2.2. Basic Operation of SCRAM

     SCRAM is built using only a simple one-way hash function, the HMAC
     [HMAC] construction and the exclusive-or operation.  There are
     three fundamental components to the exchange:

     o  the client key which is derived from the passphrase and salt

     o  the client verifier which is simply the one-way hash function
        applied to the client key

     o  the server key which is also derived from the passphrase and
        salt

     The server has access to the salt, client verifier and server key
     for each user.  The salt and client verifier are used to
     authenticate the client to the server and the salt and server key
     are used to authenticate the server to the client.

     The mechanism relies on the one-way characteristic of the hash
     function to assure that the client key can't be derived from the
     client verifier and that the server key can't be derived from
     either the client key or client verifier.

     SCRAM uses HMAC to sign client and server nonces with the client
     verifier to produce a shared key.  The client exclusive-ors the
     shared key with the client key and sends that to the server which
     uses the shared key to reverse the exclusive-or operation, extract
     the client key, and then verify that the hash function applied to
     the client key matches the client verifier.  The server uses HMAC
     to sign the client and server nonces with the server key and sends
     that to the client to authenticate.

2.3. Intended Use

     SCRAM is designed for a usage scenario where simplicity and/or
     speed is important, frequent authentications may occur and the



Newman                                                          [Page 3]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


     primary threat is passive and active network attacks.  A good
     example of protocols whose usage and threat model fit SCRAM are
     IMAP [IMAP4] and POP3 [POP3].  SCRAM provides limited protection
     against threats to the server authentication database, but OTP
     [OTP] may be preferable for usage scenarios where the threat to the
     server is more serious and active attacks are not an issue.


3. Client Implementation of SCRAM-MD5

     This section includes a step-by-step guide for client implementors.
     Section 6 contains the formal definition of the syntax and is the
     authoritative reference in case of errors here.

     When used with SASL the mechanism name is "SCRAM-MD5".  The
     mechanism does not provide a privacy layer, but does include an
     optional integrity protection layer.

     The client begins by sending a message to the server containing the
     following three pieces of information.

     (1) An authorization identity.  When the empty string is used, this
     defaults to the authentication identity.  This is used by system
     administrators or proxy servers to login with a different user
     identity.  This field may be up to 255 octets and is terminated by
     a NUL (0) octet.  US-ASCII printable characters are preferred,
     although UTF-8 [UTF-8] printable characters are permitted to
     support international names.  Use of character sets other than
     US-ASCII and UTF-8 is forbidden.

     (2) An authentication identity.  The identity whose passphrase will
     be used.  This field may be up to 255 octets and is terminated by a
     NUL (0) octet.  US-ASCII printable characters are preferred,
     although UTF-8 [UTF-8] printable characters are permitted to
     support international names.  Use of character sets other than
     US-ASCII and UTF-8 is forbidden.

     (3) A "client nonce."  It is important that this be globally
     unique.  One common technique for generating globally unique
     identifiers combines a process identifier with the system clock, a
     sequence number, a random number and the client's domain name.  The
     random number is important as clocks are often synchronized using
     insecure protocols and are predictable.  Advice for generating good
     random numbers can be found in [RANDOM].

     The server responds by sending a message containing three pieces of
     information:




Newman                                                          [Page 4]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


     (4) An 8-octet salt value, specific to the authentication identity.

     (5) A one-octet bit-mask specifying security layers supported by
     the server.  Bit 0 (value 1) indicates support for no security
     layer and bit 1 (value 2) indicates support for an integrity
     protection layer.  The other bits are reserved for future use (the
     server MUST set them to zero until they are defined in a standards
     track specification).  If the client doesn't support a security
     layer and bit 0 is cleared, then the authentication immediately
     fails.

     (6) A three-octet number in network byte order (big endian),
     containing the maximum cipher-text buffer size the server is able
     to receive.  This may be 0 if the server supports no security
     layers.

     (7) A service id consisting of the service name of the protocol's
     SASL profile followed by an "@" followed by the domain name of the
     server and terminated by NUL.  The client SHOULD verify this is
     correct.

     (8) A "server nonce".  As the domain name is included in (7), this
     only has to be unique to the server.

     The client then does the following:

     (A) Create a buffer containing the user's passphrase.  The client
     MUST support passphrases of at least 64 octets.  US-ASCII
     characters are preferred, although UTF-8 characters are permitted.
     Character sets other than US-ASCII and UTF-8 MUST NOT be used.

     (B) Apply the HMAC-MD5 function with (A) as the key and the 8-octet
     salt as the data, producing a 16-octet result.  Once this is done,
     (A) SHOULD be erased from memory.

     (C) Apply the MD5 function to the result of (B).  This produces a
     16-octet result.

     (D) Apply the MD5 function to the result of (C).  This produces a
     16-octet result.

     (E) Create a buffer containing the server's response (4)-(8),
     immediately followed by the initial client message (1)-(3) and the
     client's security layer selection (9)-(10) below.

     (F) Apply the HMAC-MD5 function with the result of (D) as the key
     and the buffer from (E) as the data.  This produces a 16-octet
     result.



Newman                                                          [Page 5]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


     (G) Create a 16-octet buffer containing the exclusive-or of (C) and
     (F).

     The client then sends a message to the server containing the
     following:

     (9) A bit-mask indicating the client selected security layer from
     step (5).  This has a value of 01 for no security layer and 02 for
     an integrity protection layer.

     (10) A three octet number indicating the maximum cipher-text buffer
     size the client is able to receive in network byte order.  If the
     client doesn't select a security layer, this may be all zeros.

     (11) The 16-octet result of step (G).

     The server will respond with:

     (12) A 16-octet server authentication verifier.

     The client SHOULD verify this with the following procedure:

     (H) Apply the HMAC-MD5 function with the result of (B) as the key
     and the 8-octet salt as the data.  This produces a 16-octet result.

     (I) Create a buffer containing the initial client message (1)-(3)
     immediately followed by the initial server response (4)-(8) and the
     client's security layer selection (9)-(10).

     (J) Apply the HMAC-MD5 function with the result of (H) as the key
     and the buffer from (I) as the data.

     (K) If the result of (J) matches (12), the server is authenticated.

     A secured client MAY store the result of (B) to re-authenticate to
     services using the same salt, or the intermediate HMAC state from
     (B) to re-authenticate to any service.  Clients SHOULD NOT store
     the passphrase itself.

     If integrity protection is negotiated on, the following procedure
     is applied to each SASL security layer packet sent by the client:

     (L) Apply the HMAC-MD5 function with the output of step (C) as the
     key and the buffer from step (E) as the value.

     (M) A buffer is created containing a four octet client packet
     number in network byte order followed by the 16-octet output of
     step (L).  The first packet sent under the SASL security layer is



Newman                                                          [Page 6]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


     given number 1.

     (N) Apply the HMAC-MD5 function with (M) as the key and the
     contents of the packet as the data.  The result is appended to the
     end of the packet.

     The integrity protection on packets from the server is verified as
     follows:

     (O) A buffer is created containing a four octet server packet
     number in network byte order followed by the 16-octet output of
     step (L) above.  This first packet sent under the SASL security
     layer is given number 1.

     (P) Apply the HMAC-MD5 function with (O) as the key and all but the
     last 16 octets of the packet as the value.

     (Q) Compare the last 16 octets of the packet to the output of (P).
     If they do not match, an integrity error is produced.


4. Server Implementation of SCRAM-MD5

     The section includes a step-by-step guide for server implementors
     building on the previous section.  Section 6 contains the formal
     definition of the syntax and is the authoritative reference in case
     of errors here.

     The server's authentication database contains an 8-octet salt,
     16-octet client verifier and a 16-octet server key for each local
     user.  The server MUST support "user@host" syntax for the
     authentication identity at least to the extent of stripping "@host"
     when it matches the local host name or rejecting the authentication
     if the host name doesn't match.  The server MAY support remote user
     authentication using this syntax.

     The stored client verifier is equal to the result of step (D)
     above, and the stored server key is equal to the result of step (H)
     above.  To create its initial response, the server simply looks up
     the authentication identity to fetch the salt, and generates an 8
     to 248 octet nonce. This nonce MUST be unique for the server to
     prevent replay attacks.  It can be generated by appending a system
     clock to a process and/or thread identifier and a random number
     [RANDOM].  To verify the client's credentials, the server performs
     the following steps:

     (a) Generate a buffer identical to step (E) above.




Newman                                                          [Page 7]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


     (b) Apply the HMAC-MD5 function with the stored client verifier as
     the key and the result of (a) as the data.  This produces a
     16-octet result equal to step (F) above.

     (c) Exclusive-or the result of (b) with message (11) from the
     client.  This produces a 16-octet result which should be equal to
     the result of step (C) above.

     (d) Apply the MD5 function to the output of step (c).  This
     produces a 16-octet result which should be equal to the result of
     step (D) above.

     (e) if the result of (d) is equal to the stored verifier, then the
     user is authenticated.

     If no client challenge was provided in step (3), the server is now
     done and responds with the appropriate status code.  Otherwise the
     server continues as follows:

     (f) Generate a buffer identical to step (I) above.

     (g) Apply the HMAC-MD5 function with the stored server verifier as
     the key and the buffer from (f) as the data.  This produces a
     16-octet result.

     The result of (g) is sent to the client to authenticate the server.

     If integrity protection is negotiated on, the integrity key is
     computed as follows:

     (h) Apply the HMAC-MD5 function with the output of step (c) as the
     key and the buffer from step (a) as the data.

     Integrity generation and verification works in the same fashion as
     the client.


5. Example

     In these examples, "C:" represents lines sent from the client to
     the server and "S:" represents lines sent from the server to the
     client.  The wrapped lines are for editorial clarity -- there are
     no actual newlines in the middle of the messages.

     The following is an example of the SCRAM-MD5 mechanism using the
     IMAP [IMAP4] profile of SASL.  For this example, the user "chris",
     with an empty authorization identity is using the passphrase
     "secret stuff".  The client nonce is



Newman                                                          [Page 8]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


     "<t4n4Pab9HB0Am/QLXB72eg@eleanor.innosoft.com>" and the server
     nonce is "jhcNZlRuPbziFp+vLV+NCw".  No security layer is supported,
     the salt is "testsalt" and the service identity is
     "imap@eleanor.innosoft.com".  The complete 40 octet verifier stored
     on the server, in hexadecimal is "74657374 73616c74 16484d56
     7ee02f47 ac5f8a5a d5795570 90d55334 d2002df6 24cb8c8b 75708f4e."

       C: a001 AUTHENTICATE SCRAM-MD5
       S: +
       C: AGNocmlzADx0NG40UGFiOUhCMEFtL1FMWEI3MmVnQGVsZWFub3IuaW
          5ub3NvZnQuY29tPg==
       S: + dGVzdHNhbHQBAAAAaW1hcEBlbGVhbm9yLmlubm9zb2Z0LmNvbQBq
          aGNOWmxSdVBiemlGcCt2TFYrTkN3
       C: AQAAAMg9jU8CeB4KOfk7sUhSQPs=
       S: + U0odqYw3B7XIIW0oSz65OQ==
       C:
       S: a001 OK AUTHENTICATE completed

     Note that base64 encoding and the lack of an initial client
     response with the first command are characteristics of the IMAP
     profile of SASL and not characteristics of SASL or SCRAM-MD5.  Here
     is another example using the ACAP [ACAP] profile of SASL.  This
     uses the same salt, passphrase and verifier as the previous
     example.  In this example, binary data is represented as
     hexadecimal digits enclosed in square brackets:

       C: a001 AUTHENTICATE "SCRAM-MD5" {52}
       C: [00]chris[00]<HSMDKNj0yFGa8f5swzqznw@eleanor.innosoft.com>
       S: + {60}
       S: testsalt[01000000]acap@eleanor.innosoft.com[00]
          m6HdEYWZA5W8keNbiY40aA
       C: {20}
       C: [01000000 19b66406 4ce8138a e0af7b0b f0ed20ea]
       S: a001 OK (SASL {16}
       S: [44d7c1c4 0630fea6 5c49cb40 717a2ba5]) "Successful"

     Note that arbitrary binary values may be used for the salt and
     nonces, as long as the client nonce is globally unique.


6. Formal Syntax of SCRAM-MD5 Messages

     This is the formal syntactic definition of the client and server
     messages.  This uses ABNF [ABNF] notation including the core rules.

     client-msg-1     = [authorize-id] NUL authenticate-id NUL nonce

     server-msg-1     = salt security-info service-id NUL nonce



Newman                                                          [Page 9]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


     client-msg-2     = security-info client-proof

     server-msg-2     = server-proof

     passphrase       = *UTF8-SAFE
                        ;; At least 64 octets MUST be supported

     authorize-id     = *UTF8-PRINT
                        ;; No more than 255 octets

     authenticate-id  = *UTF8-PRINT
                        ;; No more than 255 octets

     security-info    = secbits bufsize

     bufsize          = 3OCTET
                        ;; in network byte order (big-endian)

     secbits          = OCTET
                        ;; bit 0 = no protection, bit 1 = integrity,
                        ;; other bits set to 0 and reserved

     service-id       = service-name "@" server-domain

     service-name     = *VCHAR
                        ;; a SASL/GSSAPI service name

     server-domain    = *VCHAR
                        ;; an internet domain name

     nonce            = 8*OCTET

     salt             = 8OCTET

     client-proof     = 16OCTET

     server-proof     = 16OCTET

     NUL              = %x00  ;; US-ASCII NUL character

     UTF8-SAFE        = %x01-09 / %x0B-0C / %x0E-7F / UTF8-MULTI
                        ;; Any character except CR, LF, NUL

     UTF8-PRINT       = %x20-7E / UTF8-MULTI
                       ;; Any character except CTLs

     UTF8-MULTI       = UTF8-2 / UTF8-3 / UTF8-4 / UTF8-5 / UTF8-6
                        ;; UTF-8 Multi-octet characters



Newman                                                         [Page 10]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


     UTF8-1          = %x80-BF

     UTF8-2          = %xC0-DF UTF8-1

     UTF8-3          = %xE0-EF 2UTF8-1

     UTF8-4          = %xF0-F7 3UTF8-1

     UTF8-5          = %xF8-FB 4UTF8-1

     UTF8-6          = %xFC-FD 5UTF8-1


7. System Administrator Advice

     This section includes advice for system administrators using this
     mechanism.

     A SCRAM server stores three pieces of information for each user: a
     salt, a client verifier and server key.  The latter two are derived
     from the salt and the user's passphrase.

     The salt prevents global dictionary attacks, similar to the salt
     used in Unix /etc/passwd files.  As the 12 bits of salt in Unix
     /etc/passwd has proved to be insufficient, SCRAM uses 64 bits of
     salt.  See [SCHNEIER] for a good discussion of salt and dictionary
     attacks.  In a multi-server site, security can be increased by
     using a different salt on each server.

     Although the verifiers used by SCRAM-MD5 have roughly comparable
     security to those used by current plain-text mechanisms (such as
     Unix /etc/passwd), it is still very important to keep them secret.
     Just as tools exist to try common passwords against Unix
     /etc/passwd files, it is also possible to build such tools for
     SCRAM-MD5.  In addition, once a SCRAM-MD5 verifier is stolen, a
     passive (undetectable) eavesdropper of that user logging in gains
     the output of step (C) above, which is sufficient to impersonate
     the user to all services with the same salt.  This is better than
     current plain-text mechanisms where a passive eavesdropper always
     recovers the user's password, but is still a serious concern.

     Verifiers SHOULD be kept hidden from all users on the server.
     Sites which distribute verifiers among multiple servers, SHOULD
     encrypt them when transferring them over the network.

     SCRAM-MD5 is only a good mechanism if passphrases are well chosen.
     For this reason, implementations should use the term "passphrase"
     rather than "password" and when a user's passphrase is set, site



Newman                                                         [Page 11]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


     policy restrictions should be applied.  A reasonably secure site
     policy would require passphrases of at least 10 characters with at
     least one non-alphanumeric character.

     SCRAM-MD5 doesn't protect the privacy of data exchanged after
     authentication.  Use of TLS [TLS], IP security ESP [IPESP] or a
     stronger SASL mechanism such as Kerberos is encouraged if this
     functionality is needed.


8. SCRAM Functional Notation

     This section is designed to provide a quick understanding of SCRAM
     for those who like functional notation.

     +         octet concatenation
     XOR       the exclusive-or function
     AU        is the authentication user identity (NUL terminated)
     AZ        is the authorization user identity (NUL terminated)
               if AZ is the same as AU, a single NUL is used instead.
     csecinfo  client security layer option bits and buffer size
     ssecinfo  server security layer option bits and buffer size
     service   is the name of the service and server (NUL terminated)
     pass      is the plain-text passphrase
     H(x)      is a one-way hash function applied to "x", such as MD5
     MAC(x,y)  is a message authentication code (MAC) such as HMAC-MD5
               "y" is the key and "x" is the text signed by the key.
     salt      is a per-user salt value the server stores
     Us        is a unique nonce the server sends to the client
     Uc        is a unique nonce the client sends to the server

     The SCRAM computations and exchange are as follows:

     client-msg-1     = AZ + AU + Uc
     (1) client -> server: client-msg-1
     server-msg-1     = salt + ssecinfo + service + Us
     (2) server -> client: server-msg-1
     salted-pass      = MAC(salt, pass)
     client-key       = H(salted-pass)
     client-verifier  = H(client-key)
     shared-key       = MAC(server-msg-1 + client-msg-1 + csecinfo,
                            client-verifier)
     client-proof     = client-key XOR shared-key
     (3) client -> server: csecinfo + client-proof
     server-key       = MAC(salt, salted-pass)
     server-proof     = MAC(client-msg-1 + server-msg-1 + csecinfo,
                            server-key)
     (4) server -> client: server-proof



Newman                                                         [Page 12]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


     integrity-key    = MAC(server-msg-1 + client-msg-1 + csecinfo,
                            client-key)

     The server stores the salt, client-verifier and server-key.  It
     authenticates the client by computing:

       H(client-proof XOR shared-key)

     after step 3 and comparing it to the stored client-verifier.  The
     server computes the integrity-key with:

       MAC(server-msg-1 + client-msg-1, client-proof XOR shared-key)

     The client verifies the server by computing the server-proof
     directly and comparing.


9. Security Considerations

     Security considerations are discussed throughout this document.
     The security considerations of MD5 [MD5] and HMAC [HMAC] also
     apply.  SCRAM relies primarily on the one-way characteristic of MD5
     and HMAC-MD5 for security.  The weaknesses found in MD5 are not
     believed to impact this use.  In the interest of avoiding
     proliferation of authentication mechanisms, it is hoped that it
     will be easy to deploy public-key technology before a hash function
     upgrade becomes necessary.

     SCRAM does use the output of an HMAC function and exclusive-or to
     construct a simple 16-octet encryption function.  While
     constructing an encryption function from a hash function is
     normally a questionable practice [SCHNEIER], in this case both the
     key and the data are outputs of a one-way hash function with a good
     bit-distribution and the key is used only once (as long as the
     combined nonces are unique).

     An analysis of different attacks follows:

     Passive Network Attacks

     SCRAM is resistant to replay attacks as long as the appropriate
     nonce is unique.

     SCRAM is not resistant to passive dictionary attacks.  User
     education, passphrase setting policy and external confidentiality
     services can be used to protect against such attacks.

     SCRAM does not protect against session data eavesdropping.  An



Newman                                                         [Page 13]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


     external confidentiality service is necessary to protect against
     eavesdropping.  TLS [TLS] and IP security ESP [IPESP] are examples
     of IETF standards-track mechanisms to provide confidentiality.

     Active Network Attacks

     If the client fails to verify the server proof, then SCRAM provides
     no protection from active attacks.

     SCRAM protects against server impersonation with the server mutual
     authentication.

     An attacker could use SCRAM to probe for users by trying each user
     name twice to see if the salt varies.  The server can prevent this
     attack by inventing consistent salt values for non-users.  One way
     to do this would be to store a random secret and generate the salt
     using HMAC(user-name, random-secret).

     SASL is susceptible to downgrade active attacks which reduce the
     advertised authentication mechanisms to the weakest the server
     offers.  If SCRAM is the weakest mechanism, such attacks can be
     detected if integrity protection is negotiated on and the client
     requests a duplicate copy of the server's capability list after
     authentication (e.g., by re-issuing the CAPABILITY command in
     IMAP).  For a protocol such as ACAP [ACAP], the server SHOULD
     repeat the greeting line immediately after authentication is
     completed whenever integrity protection is negotiated on.

     SCRAM can detect insertion, deletion and modification of session
     data only if integrity protection is negotiated on.  TLS [TLS] or
     IP security services [IPAUTH, IPESP] may also be used to protect
     against such tampering.  If TLS or IP security integrity protection
     is active, then the SCRAM integrity layer is unnecessary and SHOULD
     be negotiated off.

     Upper level security services, such as SCRAM and TLS, can not
     protect against denial of service attacks on the TCP/IP layer.  In
     addition, if no integrity layer is used, then SCRAM is vulnerable
     to TCP session stealing attacks [CERT-IPSPOOF].  IP security
     services [IPAUTH, IPESP] can protect against many of these attacks.

     SCRAM is not susceptible to the race and denial of service attacks
     mentioned in section 9 of the OTP specification [OTP].

     Server Attacks

     A server implementation which does not tolerate input of any length
     with any content may be susceptible to attacks which permit



Newman                                                         [Page 14]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


     privileged access to the server.  For this reason server
     implementations MUST be able to accept input of any length with any
     content although server implementations MAY refuse to authenticate
     the client if messages exceed the specified maximum lengths.  Note
     that the ANSI C gets() library function does not meet this
     requirement.

     An attacker which has access to both the SCRAM verifier and a
     client exchange for a particular user gains the ability to
     impersonate that user to other servers using the same salt.  An
     external confidentiality service can make it more difficult to
     obtain the client exchange, but can not defend against installation
     of a trojan horse on a compromised server.

     In the process of authentication, the server gains access to the
     client-key which is sufficient to impersonate the user to other
     services with the same salt.

     The limited service trust feature (step 7 above) includes the
     service name and the server host name.  A server host which is
     authorized to provide one service can impersonate that service at
     other hosts in the same realm by an active attack on the DNS system
     when used by the client.  Use of secure DNS [DNSSEC] on the client
     limits this vulnerability.

     Client Attacks

     As SCRAM is designed for user entry of a plain-text passphrase, it
     is vulnerable to passphrase hijacking by trojan horse clients.  OTP
     [OTP] with an external portable OTP calculator can limit the
     vulnerability to a single session.


10. Intellectual Property Issues and Prior Art

     The author is not aware of any patents or pending patents which
     apply to this mechanism.

     This is primarily a derivative of simple hash-based challenge
     response systems.  The hash-based challenge response idea has
     existed since at least 1992, when the RIPE project published the
     SKID algorithm according to [SCHNEIER].

     The repeated-hash idea used to verify the client's authenticator is
     derived from S/KEY [SKEY].

     The idea of using salt to protect against global dictionary attacks
     dates back to at least the Unix /etc/passwd system.  There is some



Newman                                                         [Page 15]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


     discussion of this in [SCHNEIER].

     SCRAM combines these techniques.  The author of this specification
     first proposed this idea on a public mailing list on July 16, 1997.


11. Multinational Considerations

     As remote access is a crucial service, users are encouraged to
     restrict user names and passphrases to the US-ASCII character set.
     However, if characters outside the US-ASCII character set are used
     in user names and passphrases, then they are interpreted according
     to UTF-8 [UTF-8] and it is a protocol error to include any octet
     sequences not legal for UTF-8.  Servers are encouraged to enforce
     this restriction to discourage clients which use unlabeled
     character sets in this context.


12. References

     [ABNF] Crocker, Overell, "Augmented BNF for Syntax Specifications:
     ABNF", RFC 2234, Internet Mail Consortium, Demon Internet Ltd,
     November 1997.

     [ACAP] Newman, Myers, "ACAP -- Application Configuration Access
     Protocol", RFC 2244, Innosoft, Netscape, November 1997.

     [CERT-IPSPOOF] CERT, "TCP SYN Flooding and IP Spoofing Attacks",
     CERT CA-96.21, CERT, September 1996.

     [CRAM-MD5] Klensin, Catoe, Krumviede, "IMAP/POP AUTHorize Extension
     for Simple Challenge/Response", RFC 2195, MCI, September 1997.

     [DNSSEC] Eastlake, Kaufman, "Domain Name System Security
     Extensions", RFC 2065, CyberCash, Iris, January 1997.

     [HMAC] Krawczyk, Bellare, Canetti, "HMAC: Keyed-Hashing for Message
     Authentication", RFC 2104, IBM, UCSD, February 1997.

     [IMAP4] Crispin, M., "Internet Message Access Protocol - Version
     4rev1", RFC 2060, University of Washington, December 1996.

     [IPAUTH] Atkinson, "IP Authentication Header", RFC 1826, Naval
     Research Laboratory, August 1995.

     [IPESP] Atkinson, "IP Encapsulating Security Payload (ESP)", RFC
     1827, Naval Research Laboratory, August 1995.




Newman                                                         [Page 16]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


     [KEYWORDS] Bradner, "Key words for use in RFCs to Indicate
     Requirement Levels", RFC 2119, Harvard University, March 1997.

     [MD5] Rivest, "The MD5 Message Digest Algorithm", RFC 1321, MIT
     Laboratory for Computer Science, April 1992.

     [OTP] Haller, Metz, "A One-Time Password System", RFC 1938,
     Bellcore, Kaman Sciences Corporation, May 1996.

     [OTP-EXT] Metz, "OTP Extended Responses", RFC 2243, The Inner Net,
     November 1997.

     [POP3] Myers, J., Rose, M., "Post Office Protocol - Version 3", RFC
     1939, Carnegie Mellon, Dover Beach Consulting, Inc., May 1996.

     [RANDOM] Eastlake, Crocker, Schiller, "Randomness Recommendations
     for Security", RFC 1750, DEC, Cybercash, MIT, December 1994.

     [SASL] Myers, "Simple Authentication and Security Layer (SASL)",
     RFC 2222, Netscape Communications, October 1997.

     [SCHNEIER] Schneier, "Applied Cryptography: Protocols, Algorithms
     and Source Code in C," John Wiley and Sons, Inc., 1996.

     [SKEY] Haller, Neil M. "The S/Key One-Time Password System", RFC
     1760, Bellcore, February 1995.

     [TLS] Dierks, Allen, "The TLS Protocol Version 1.0", Work in
     progress.

     [UTF8] Yergeau, F. "UTF-8, a transformation format of ISO 10646",
     RFC 2279, Alis Technologies, January 1998.


13. Author's Address

     Chris Newman
     Innosoft International, Inc.
     1050 Lakes Drive
     West Covina, CA 91790 USA

     Email: chris.newman@innosoft.com


A. Appendix - Additional Services

     Several additional services are needed to make SCRAM useful in more
     usage scenarios.  These include remote authentication database



Newman                                                         [Page 17]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


     support for servers, authentication database APIs for servers,
     remote passphrase change support for clients, single-sign-on APIs
     for clients and management tools.  The service-id and server-key
     are included to facilitate the remote authentication database
     service.  Otherwise these issues are deferred for future work.

B. Appendix - HMAC-MD5 Sample Source Code

     The following sample C source code calls the source code in the MD5
     specification [MD5] and is derived from the source code in [HMAC].
     It is needed by the SCRAM source code in the next section.

     The client may call hmac_md5_precalc() to save the intermediate
     HMAC result for later use in hmac_md5_import().  This can be used
     by a CRAM-MD5 [CRAM-MD5] or a SCRAM-MD5 [SCRAM-MD5] client to save
     an intermediate result suitable for use with any server without
     saving the plain-text passphrase.

     /* hmac-md5.h -- HMAC_MD5 functions
      */
     #define HMAC_MD5_SIZE 16

     /* intermediate MD5 context */
     typedef struct HMAC_MD5_CTX_s {
         MD5_CTX ictx, octx;
     } HMAC_MD5_CTX;

     /* intermediate HMAC state
      *  values stored in network byte order (Big Endian)
      */
     typedef struct HMAC_MD5_STATE_s {
         UINT4 istate[4];
         UINT4 ostate[4];
     } HMAC_MD5_STATE;

     /* One step hmac computation
      *
      * digest may be same as text or key
      */
     void hmac_md5(const unsigned char *text, int text_len,
                const unsigned char *key, int key_len,
                unsigned char digest[HMAC_MD5_SIZE]);

     /* create context from key
      */
     void hmac_md5_init(HMAC_MD5_CTX *hmac,
             const unsigned char *key, int key_len);




Newman                                                         [Page 18]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


     /* precalculate intermediate state from key
      */
     void hmac_md5_precalc(HMAC_MD5_STATE *hmac,
                const unsigned char *key, int key_len);

     /* initialize context from intermediate state
      */
     void hmac_md5_import(HMAC_MD5_CTX *hmac, HMAC_MD5_STATE *state);

     #define hmac_md5_update(hmac, text, text_len) \
       MD5Update(&(hmac)->ictx, (text), (text_len))

     /* finish hmac from intermediate result.
      *  Intermediate result is erased.
      */
     void hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE],
              HMAC_MD5_CTX *hmac);


     /* hmac-md5.c -- HMAC MD5 Keyed-Hashing by Chris Newman
      *  derived from RFC 2104 by H. Krawczyk, M. Bellare, R.Canetti
      */
     #include <stdio.h>
     #include <string.h>
     #include "md5.h"
     #include "hmac-md5.h"

     /* for htonl() and ntohl() */
     #include <sys/types.h>
     #include <netinet/in.h>

     /* MD5 block size */
     #define BLOCK_SIZE 64

     void hmac_md5_init(HMAC_MD5_CTX *hmac,
             const unsigned char *key, int key_len)
     {
         unsigned char k_pad[BLOCK_SIZE];    /* padded key */
         int i;

         /* if key longer than BLOCK_SIZE bytes reset to MD5(key) */
         if (key_len > BLOCK_SIZE) {
          MD5Init(&hmac->ictx);
          MD5Update(&hmac->ictx, key, key_len);
          MD5Final(k_pad, &hmac->ictx);
          key = k_pad;
          key_len = HMAC_MD5_SIZE;
         }



Newman                                                         [Page 19]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998



         /* XOR padded key with inner pad value */
         for (i = 0; i < key_len; i++) {
          k_pad[i] = key[i] ^ 0x36;
         }
         while (i < BLOCK_SIZE) {
          k_pad[i++] = 0x36;
         }

         /* Begin inner MD5 */
         MD5Init(&hmac->ictx);
         MD5Update(&hmac->ictx, k_pad, BLOCK_SIZE);

         /* XOR padded key with outer pad value */
         for (i = 0; i < BLOCK_SIZE; ++i) {
          k_pad[i] ^= (0x36 ^ 0x5c);
         }

         /* Begin outer MD5 */
         MD5Init(&hmac->octx);
         MD5Update(&hmac->octx, k_pad, BLOCK_SIZE);

         /* clean up workspace */
         memset(k_pad, 0, BLOCK_SIZE);
     }

     void hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE],
              HMAC_MD5_CTX *hmac)
     {
         /* finish inner MD5 */
         MD5Final(digest, &hmac->ictx);
         /* finish outer MD5 */
         MD5Update(&hmac->octx, digest, HMAC_MD5_SIZE);
         MD5Final(digest, &hmac->octx);
         /* MD5Final zeros context */
     }

     void hmac_md5(const unsigned char *text, int text_len,
                const unsigned char *key, int key_len,
                unsigned char digest[HMAC_MD5_SIZE])
     {
         HMAC_MD5_CTX hmac;

         hmac_md5_init(&hmac, key, key_len);
         hmac_md5_update(&hmac, text, text_len);
         hmac_md5_final(digest, &hmac);
     }




Newman                                                         [Page 20]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


     void hmac_md5_precalc(HMAC_MD5_STATE *ctx,
          const unsigned char *pass, int passlen)
     {
         HMAC_MD5_CTX hctx;

         if (passlen == 0) passlen = strlen((const char *) pass);
         hmac_md5_init(&hctx, pass, passlen);
         ctx->istate[0] = htonl(hctx.ictx.state[0]);
         ctx->istate[1] = htonl(hctx.ictx.state[1]);
         ctx->istate[2] = htonl(hctx.ictx.state[2]);
         ctx->istate[3] = htonl(hctx.ictx.state[3]);
         ctx->ostate[0] = htonl(hctx.octx.state[0]);
         ctx->ostate[1] = htonl(hctx.octx.state[1]);
         ctx->ostate[2] = htonl(hctx.octx.state[2]);
         ctx->ostate[3] = htonl(hctx.octx.state[3]);
         memset(&hctx, 0, sizeof (hctx));
     }


     void hmac_md5_import(HMAC_MD5_CTX *hctx, HMAC_MD5_STATE *ctx)
     {
         hctx->ictx.state[0] = ntohl(ctx->istate[0]);
         hctx->ictx.state[1] = ntohl(ctx->istate[1]);
         hctx->ictx.state[2] = ntohl(ctx->istate[2]);
         hctx->ictx.state[3] = ntohl(ctx->istate[3]);
         hctx->octx.state[0] = ntohl(ctx->ostate[0]);
         hctx->octx.state[1] = ntohl(ctx->ostate[1]);
         hctx->octx.state[2] = ntohl(ctx->ostate[2]);
         hctx->octx.state[3] = ntohl(ctx->ostate[3]);
         hctx->ictx.count[0] = hctx->octx.count[0] = BLOCK_SIZE << 3;
         hctx->ictx.count[1] = hctx->octx.count[1] = 0;
     }



















Newman                                                         [Page 21]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


C. Appendix - SCRAM sample source code

     The following sample source code implements SCRAM itself for both
     server and client.

     Please note the lines marked "XXX: ..." as they need to be
     translated from English to computer readable code.

     A client implementation simply calls scram_md5_generate() with the
     passphrase after receiving the first server reply.  The cproof
     parameter will hold the message to send to the server and the
     sproof parameter will hold the expected server mutual
     authentication.  The clidata parameter holds the client's security
     layer selections.  A client may also call hmac_md5_precalc() to
     turn a passphrase into CRAM/SCRAM credentials for later use in
     scram_md5_generate().

     A server implementation simply calls scram_md5_generate() with the
     stored verifier, the second client message and the SCRAM_VERIFY
     option.  Server verifiers are generated by creating a random salt
     and calling scram_md5_vgen() with either the passphrase or
     CRAM/SCRAM credentials.

     If integrity protection is desired, the integrity_key parameter may
     be provided to scram_md5_generate() and will receive the resulting
     key.  Generating an verifying the integrity protection is left as
     an exercise to the reader.

     /* scram.h -- scram utility functions
      */
     /* size of SCRAM_MD5 salt and verifier */
     #define SCRAM_MD5_SALTSIZE 8
     #define SCRAM_MD5_DATASIZE 16

     /* SCRAM verifier */
     typedef struct SCRAM_MD5_VRFY_s {
         unsigned char salt[SCRAM_MD5_SALTSIZE];
         unsigned char clidata[SCRAM_MD5_DATASIZE];
         unsigned char svrdata[SCRAM_MD5_DATASIZE];
     } SCRAM_MD5_VRFY;

     /* Client proof message */
     typedef struct SCRAM_MD5_CLIENT_s {
         unsigned char secprops[4];
         unsigned char cproof[SCRAM_MD5_DATASIZE];
     } SCRAM_MD5_CLIENT;

     /* generate SCRAM-MD5 verifier



Newman                                                         [Page 22]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


      *  vptr      -- gets result
      *  salt      -- contains salt of SCRAM_MD5_SALTSIZE
      *  pass      -- passphrase or verifier
      *  passlen   -- len of pass/verifier (0 ok if NUL terminated)
      *  plainflag -- 1 = plaintext passphrase,
      *               0 = result of hmac_md5_precalc()
      *  clientkey -- cache for client proof, usually NULL
      */
     void scram_md5_vgen(SCRAM_MD5_VRFY *vptr,
                         const unsigned char *salt,
                         const char *pass, int passlen, int plainflag,
                         unsigned char *clientkey);

     /* scram secret action type */
     #define SCRAM_CREDENTIAL 0 /* generate replies using credentials */
     #define SCRAM_PLAINTEXT  1 /* generate replies using plaintext */
     #define SCRAM_VERIFY     2 /* use SCRAM_MD5_VRFY to verify client,
                                   and generate server reply */

     /* generate or verify SCRAM-MD5
      * input params:
      *  cchal         -- client challenge string
      *  cchallen      -- length of client challenge
      *  schal         -- server challenge string
      *  schallen      -- length of server challenge
      *  secret        -- passphrase, credentials, or verifier
      *  secretlen     -- length of passphrase (0 ok if NUL terminated)
      *  action        -- see above
      * in/out:
      *  clidata       -- client data for client response
      * output:
      *  sproof        -- server proof of length SCRAM_MD5_DATASIZE
      *  integrity_key -- integrity key of length SCRAM_MD5_DATASIZE
      *                   caller may pass NULL if no integrity needed
      * returns:
      *  -2 if params invalid
      *  -1 if verify fails
      *   0 on success
      */
     int scram_md5_generate(const char *cchal, int cchallen,
                            const char *schal, int schallen,
                            const char *secret, int secretlen,
                            int action,
                            SCRAM_MD5_CLIENT *clidata,
                            unsigned char *sproof,
                            unsigned char *integrity_key);





Newman                                                         [Page 23]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


     /* scram.c -- routines for SCRAM-MD5 calculations
      */
     #include <stdio.h>
     #include <stdlib.h>
     #include <string.h>
     #include "md5.h"
     #include "hmac-md5.h"
     #include "scram.h"

     void scram_md5_vgen(SCRAM_MD5_VRFY *vptr,
                         const unsigned char *salt,
                         const char *pass, int passlen, int plainflag,
                         unsigned char *clientkey)
     {
         HMAC_MD5_CTX hctx;

         if (clientkey == NULL) clientkey = vptr->clidata;

         /* get context */
         if (plainflag) {
             if (passlen == 0) passlen = strlen(pass);
             hmac_md5_init(&hctx, (const unsigned char *) pass,
                           passlen);
         } else {
             hmac_md5_import(&hctx, (HMAC_MD5_STATE *) pass);
         }

         /* generate salted passphrase */
         hmac_md5_update(&hctx, salt, SCRAM_MD5_SALTSIZE);
         hmac_md5_final(vptr->clidata, &hctx);

         /* generate server proof */
         hmac_md5(salt, SCRAM_MD5_SALTSIZE, vptr->clidata,
                  sizeof (vptr->clidata), vptr->svrdata);

         /* generate client key and client verifier */
         MD5Init(&hctx.ictx);
         MD5Update(&hctx.ictx, vptr->clidata, sizeof (vptr->clidata));
         MD5Final(clientkey, &hctx.ictx);
         MD5Init(&hctx.ictx);
         MD5Update(&hctx.ictx, clientkey, SCRAM_MD5_DATASIZE);
         MD5Final(vptr->clidata, &hctx.ictx);

         /* copy salt to verifier */
         if (salt != vptr->salt) {
             memcpy(vptr->salt, salt, SCRAM_MD5_SALTSIZE);
         }
     }



Newman                                                         [Page 24]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


     int scram_md5_generate(const char *cchal, int cchallen,
                            const char *schal, int schallen,
                            const char *secret, int secretlen,
                            int action,
                            SCRAM_MD5_CLIENT *clidata,
                            unsigned char *sproof,
                            unsigned char *integrity_key)
     {
         SCRAM_MD5_VRFY verifier, *vptr;
         HMAC_MD5_CTX hctx;
         unsigned char clientkey[HMAC_MD5_SIZE];
         unsigned char sharedkey[HMAC_MD5_SIZE];
         int i, result = 0;

         /* check params */
         if ((action == SCRAM_CREDENTIAL
           && secretlen != sizeof (HMAC_MD5_STATE))
             || (action == SCRAM_VERIFY
                 && secretlen != sizeof (verifier))
             || schallen < SCRAM_MD5_SALTSIZE) {
             return (-2);
         }

         /* get verifier */
         if (action == SCRAM_VERIFY) {
             vptr = (SCRAM_MD5_VRFY *) secret;
         } else {
             scram_md5_vgen(&verifier, (const unsigned char *) schal,
                            secret, secretlen, action, clientkey);
             vptr = &verifier;
         }

         /* calculate shared key */
         hmac_md5_init(&hctx, vptr->clidata, sizeof (vptr->clidata));
         hmac_md5_update(&hctx, (unsigned char *) schal, schallen);
         hmac_md5_update(&hctx, (unsigned char *) cchal, cchallen);
         hmac_md5_update(&hctx, clidata->secprops, 4);
         hmac_md5_final(sharedkey, &hctx);

         if (action == SCRAM_VERIFY) {
             /* verify client proof */
             for (i = 0; i < HMAC_MD5_SIZE; ++i) {
                 XXX: the line which belongs here is omitted due to
                 U.S. export regulations, but it exclusive-ors the
                 "sharedkey" with the "clidata->cproof" and places the
                 result in "clientkey" (see step (c) above)
             }
             MD5Init(&hctx.ictx);



Newman                                                         [Page 25]

Internet Draft          SCRAM-MD5 SASL Mechanism              March 1998


             MD5Update(&hctx.ictx, clientkey, sizeof (clientkey));
             MD5Final(sharedkey, &hctx.ictx);
             if (memcmp(sharedkey, vptr->clidata,
                        sizeof (sharedkey)) != 0) {
                 result = -1;
             }
         } else {
             /* generate client proof */
             for (i = 0; i < HMAC_MD5_SIZE; ++i) {
                 XXX: the line which belongs here is omitted due to
                 U.S. export regulations, but it exclusive-ors the
                 "sharedkey" with the "clientkey" and places the
                 result in "clidata->cproof" (see step (G) above)
             }
         }

         /* calculate integrity key */
         if (integrity_key != NULL) {
             hmac_md5_init(&hctx, clientkey, HMAC_MD5_SIZE);
             hmac_md5_update(&hctx, (unsigned char *) schal, schallen);
             hmac_md5_update(&hctx, (unsigned char *) cchal, cchallen);
             hmac_md5_update(&hctx, clidata->secprops, 4);
             hmac_md5_final(integrity_key, &hctx);
         }

         /* calculate server result */
         if (result == 0) {
             hmac_md5_init(&hctx, vptr->svrdata, HMAC_MD5_SIZE);
             hmac_md5_update(&hctx, (unsigned char *) cchal, cchallen);
             hmac_md5_update(&hctx, (unsigned char *) schal, schallen);
             hmac_md5_update(&hctx, clidata->secprops, 4);
             hmac_md5_final(sproof, &hctx);
         }

         /* cleanup workspace */
         memset(clientkey, 0, sizeof (clientkey));
         memset(sharedkey, 0, sizeof (sharedkey));
         if (vptr == &verifier) memset(&verifier, 0, sizeof (verifier));

         return (result);
     }










Newman                                                         [Page 26]
