idnits 2.17.1 draft-newman-auth-scram-01.txt: Checking boilerplate required by RFC 5378 and the IETF Trust (see https://trustee.ietf.org/license-info): ---------------------------------------------------------------------------- ** Cannot find the required boilerplate sections (Copyright, IPR, etc.) in this document. Expected boilerplate is as follows today (2024-04-26) according to https://trustee.ietf.org/license-info : IETF Trust Legal Provisions of 28-dec-2009, Section 6.a: This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79. IETF Trust Legal Provisions of 28-dec-2009, Section 6.b(i), paragraph 2: Copyright (c) 2024 IETF Trust and the persons identified as the document authors. All rights reserved. IETF Trust Legal Provisions of 28-dec-2009, Section 6.b(i), paragraph 3: This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License. Checking nits according to https://www.ietf.org/id-info/1id-guidelines.txt: ---------------------------------------------------------------------------- ** Missing expiration date. The document expiration date should appear on the first and last page. ** The document seems to lack a 1id_guidelines paragraph about Internet-Drafts being working documents. ** The document seems to lack a 1id_guidelines paragraph about the list of current Internet-Drafts. ** The document seems to lack a 1id_guidelines paragraph about the list of Shadow Directories. ** The document is more than 15 pages and seems to lack a Table of Contents. == No 'Intended status' indicated for this document; assuming Proposed Standard Checking nits according to https://www.ietf.org/id-info/checklist : ---------------------------------------------------------------------------- ** The document seems to lack an Introduction section. ** The document seems to lack an IANA Considerations section. (See Section 2.2 of https://www.ietf.org/id-info/checklist for how to handle the case when there are no actions for IANA.) ** The document seems to lack separate sections for Informative/Normative References. All references will be assumed normative when checking for downward references. ** There are 4 instances of too long lines in the document, the longest one being 2 characters in excess of 72. ** The abstract seems to contain references ([HMAC], [POP3], [CRAM-MD5], [IMAP4], [OTP], [SASL], [MD5]), which it shouldn't. Please replace those with straight textual mentions of the documents in question. Miscellaneous warnings: ---------------------------------------------------------------------------- == Line 433 has weird spacing: '...service is t...' == Line 434 has weird spacing: '...xt-attr serve...' == The document seems to lack the recommended RFC 2119 boilerplate, even if it appears to use RFC 2119 keywords -- however, there's a paragraph with a matching beginning. Boilerplate error? (The document does seem to have the reference to RFC 2119 which the ID-Checklist requires). -- The document seems to lack a disclaimer for pre-RFC5378 work, but may have content which was first submitted before 10 November 2008. If you have contacted all the original authors and they are all willing to grant the BCP78 rights to the IETF Trust, then this is fine, and you can ignore this comment. If not, you may need to add the pre-RFC5378 disclaimer. (See the Legal Provisions document at https://trustee.ietf.org/license-info for more information.) -- The document date (October 1997) is 9690 days in the past. Is this intentional? -- Found something which looks like a code comment -- if you have code sections in the document, please surround them with '' and '' lines. Checking references for intended status: Proposed Standard ---------------------------------------------------------------------------- (See RFCs 3967 and 4897 for information about using normative references to lower-maturity documents in RFCs) == Missing Reference: 'UTF-8' is mentioned on line 125, but not defined -- Looks like a reference, but probably isn't: '4' on line 967 -- Looks like a reference, but probably isn't: '0' on line 999 -- Looks like a reference, but probably isn't: '1' on line 1000 -- Looks like a reference, but probably isn't: '2' on line 997 -- Looks like a reference, but probably isn't: '3' on line 998 == Unused Reference: 'UTF8' is defined on line 681, but no explicit reference was found in the text -- No information found for draft-ietf-drums-abnf-xx - is the name correct? -- Possible downref: Normative reference to a draft: ref. 'ABNF' ** Downref: Normative reference to an Informational RFC: RFC 2104 (ref. 'HMAC') ** Obsolete normative reference: RFC 2060 (ref. 'IMAP4') (Obsoleted by RFC 3501) ** Obsolete normative reference: RFC 1826 (ref. 'IPAUTH') (Obsoleted by RFC 2402) ** Downref: Normative reference to an Informational RFC: RFC 1321 (ref. 'MD5') ** Obsolete normative reference: RFC 1938 (ref. 'OTP') (Obsoleted by RFC 2289) -- Possible downref: Non-RFC (?) normative reference: ref. 'OTP-EXT' ** Obsolete normative reference: RFC 1750 (ref. 'RANDOM') (Obsoleted by RFC 4086) -- Possible downref: Non-RFC (?) normative reference: ref. 'SASL' -- Possible downref: Non-RFC (?) normative reference: ref. 'SCHNEIER' ** Downref: Normative reference to an Informational RFC: RFC 1760 (ref. 'SKEY') -- Possible downref: Non-RFC (?) normative reference: ref. 'TLS' ** Obsolete normative reference: RFC 2044 (ref. 'UTF8') (Obsoleted by RFC 2279) Summary: 19 errors (**), 0 flaws (~~), 6 warnings (==), 14 comments (--). Run idnits with the --verbose option for more detailed information about the items above. -------------------------------------------------------------------------------- 2 Network Working Group C. Newman 3 Internet Draft: SCRAM-MD5 SASL Mechanism Innosoft 4 Document: draft-newman-auth-scram-01.txt October 1997 5 Expires in six months 7 Salted Challenge Response Authentication Mechanism (SCRAM) 9 Status of this memo 11 This document is an Internet-Draft. Internet-Drafts are working 12 documents of the Internet Engineering Task Force (IETF), its areas, 13 and its working groups. Note that other groups may also distribute 14 working documents as Internet-Drafts. 16 Internet-Drafts are draft documents valid for a maximum of six 17 months and may be updated, replaced, or obsoleted by other 18 documents at any time. It is inappropriate to use Internet-Drafts 19 as reference material or to cite them other than as "work in 20 progress." 22 To view the entire list of current Internet-Drafts, please check 23 the "1id-abstracts.txt" listing contained in the Internet-Drafts 24 Shadow Directories on ftp.is.co.za (Africa), ftp.nordu.net 25 (Europe), munnari.oz.au (Pacific Rim), ds.internic.net (US East 26 Coast), or ftp.isi.edu (US West Coast). 28 Abstract 30 SCRAM is a simple passphrase-based authentication mechanism 31 suitable for a wide variety of usage scenarios. It combines the 32 best properties of CRAM-MD5 [CRAM-MD5] and OTP [OTP] without a 33 significant increase in complexity. 35 This document defines the SCRAM-MD5 SASL mechanism [SASL] using the 36 MD5 [MD5] and HMAC-MD5 [HMAC] algorithms. It is suitable for use 37 directly with protocols such as IMAP [IMAP4] and POP [POP3]. 39 0. Changes from Previous Version 41 (1) MD5 is used instead of SHA1 as it permits backwards- 42 compatibility with CRAM-MD5 verifiers on the server and it is a 43 more commonly available hash function. This should not effect 44 SCRAM's security significantly. 46 (2) The server-proof is now independent of the client-verifier. 47 This allows a remote authentication service to efficiently restrict 48 the services an application server may offer to clients. 50 (3) The salt is included in the client-key which means that a 51 compromised verifier and client-server exchange only gains access 52 to services which use the same salt. 54 (4) The service identifier is simplified and separated from the 55 extension data which now has defined syntax. 57 (5) The client-nonce may be omitted for one-way authentication. 59 (6) Examples and sample source code has been added. 61 1. How to Read This Document 63 This document has information for several different audiences. 64 Section 2 describes the highlights of SCRAM. Sections 3-6 are 65 intended for implementors. Section 7 is intended for system 66 administrators. Sections 7-10 are intended for security 67 evaluation. 69 The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" 70 in this document are to be interpreted as defined in "Key words for 71 use in RFCs to Indicate Requirement Levels" [KEYWORDS]. 73 2. SCRAM Highlights 75 SCRAM is a simple passphrase-based mechanism, which does not 76 require complicated public key technology. It can be implemented 77 in a few pages of source code. 79 SCRAM is not plaintext equivalent, so it improves network security 80 over plaintext mechanisms without sacrificing security of the 81 authentication database. 83 SCRAM includes a salt to prevent global dictionary attacks on the 84 server's authentication database. 86 SCRAM supports proxy authentication by including an authorization 87 identity (user to login as) separate from the authentication 88 identity (server authentication database entry to use). 90 SCRAM supports optional mutual authentication. 92 SCRAM supports limited server trust. This means a centralized 93 authentication server can restrict the services offered by 94 application servers. 96 SCRAM-MD5 is backwards-compatible with existing CRAM-MD5 verifiers 97 stored in server authentication databases. 99 3. Client Implementation of SCRAM-MD5 101 This section includes a step-by-step guide for client implementors. 102 Although section 6 contains the formal definition of the syntax and 103 is the authoritative reference in case of errors here, this section 104 should be sufficient to build a correct implementation. 106 When used with SASL the mechanism name is "SCRAM-MD5". The 107 mechanism does not provide a security layer. 109 The client begins by sending a message to the server containing the 110 following three pieces of information. The entire message MUST NOT 111 exceed 1000 characters. 113 (1) An authorization identity. When the empty string is used, this 114 defaults to the authentication identity. This is used by system 115 administrators or proxy servers to login with a different user 116 identity. This field may be up to 255 octets and is terminated by 117 a NUL (0) octet. US-ASCII printable characters are preferred, 118 although UTF-8 [UTF-8] printable characters are permitted to 119 support international names. Use of character sets other than 120 US-ASCII and UTF-8 is forbidden. 122 (2) An authentication identity. The identity whose passphrase will 123 be used. This field may be up to 255 octets and is terminated by a 124 NUL (0) octet. US-ASCII printable characters are preferred, 125 although UTF-8 [UTF-8] printable characters are permitted to 126 support international names. Use of character sets other than 127 US-ASCII and UTF-8 is forbidden. 129 (3) An optional "client nonce." If this is omitted, it indicates a 130 desire for client-only authentication. When present, it is 131 important that this be globally unique. One common technique for 132 generating globally unique identifiers combines a process 133 identifier with the system clock, a sequence number, a random 134 number and the client's domain name. The random number is 135 important as clocks are often synchronized using insecure 136 protocols. Advice for generating strong random numbers can be 137 found in [RANDOM]. 139 The server responds by sending a message containing three pieces of 140 information. The entire message MUST NOT exceed 1000 characters. 142 (4) An 8-octet salt value, specific to the authentication identity. 144 (5) A service id consisting of the service name of the protocol's 145 SASL profile followed by an "@" followed by the domain name of the 146 server and terminated by NUL. The client SHOULD verify this is 147 correct. 149 (6) A string containing extension data, terminated by NUL. A 150 client which supports TLS [TLS] or stronger SASL mechanisms can 151 check this to protect against an active downgrade attack. A server 152 which supports TLS or stronger SASL mechanisms SHOULD advertise 153 them here. 155 (7) A "server nonce". 157 The client then does the following: 159 (A) Create a buffer containing the user's passphrase. The client 160 MUST support passphrases of at least 64 octets. US-ASCII 161 characters are preferred, although UTF-8 characters are permitted. 162 Character sets other than UTF-8 MUST NOT be used. 164 (B) Apply the HMAC-MD5 function with (A) as the key and the 8-octet 165 salt as the data, producing a 16-octet result. Once this is done, 166 (A) SHOULD be erased from memory. 168 (C) Apply the MD5 function to the result of (B). This produces a 169 16-octet result. 171 (D) Apply the MD5 function to the result of (C). This produces a 172 16-octet result. 174 (E) Create a buffer containing the server's response (4)-(7), 175 immediately followed by the initial client message (1)-(3). 177 (F) Apply the HMAC-MD5 function with the result of (D) as the key 178 and the buffer from (E) as the data. This produces a 16-octet 179 result. 181 (G) Create a 16-octet buffer containing the exclusive-or of (C) and 182 (F). 184 The client then sends a message to the server containing the 185 following: 187 (8) The 16-octet result of step (G). 189 If no client challenge was suppled in step 3, the one-way 190 authentication is now complete. 192 (9) A 16-octet server authentication verifier. 194 The client SHOULD verify this with the following procedure: 196 (H) Apply the HMAC-MD5 function with the result of (B) as the key 197 and the 8-octet salt as the data. This produces a 16-octet result. 199 (I) Create a buffer containing the initial client message (1)-(3) 200 immediately followed by the initial server response (4)-(7). 202 (J) Apply the HMAC-MD5 function with the result of (H) as the key 203 and the buffer from (I) as the data. 205 (K) If the result of (J) matches (9), the server is authenticated. 207 A secured client MAY store the result of (B) to re-authenticate to 208 services using the same salt, or the intermediate HMAC state from 209 (B) to re-authenticate to any service. Clients SHOULD NOT store 210 the passphrase itself. 212 4. Server Implementation of SCRAM-MD5. 214 The section includes a step-by-step guide for server implementors. 215 Although section 6 contains the formal definition of the syntax and 216 is the authoritative reference in case of errors here, this section 217 in conjunction with section 3 should be sufficient to build a 218 correct implementation. 220 The server's authentication database contains an 8-octet salt, 16- 221 octet client verifier and a 16-octet server key for each local 222 user. The server MUST support "user@host" syntax for the 223 authentication identity at least to the extent of stripping "@host" 224 when it matches the local hostname or rejecting the authentication 225 immediately after the initial client message if the hostname 226 doesn't match. The server MAY support remote user authentication 227 using this syntax. 229 The stored client verifier is equal to the result of step (D) 230 above, and the stored server key is equal to the result of step (J) 231 above. To create its initial response, the server simply looks up 232 the authentication identity to fetch the salt, and generates an 8 233 to 248 octet nonce. This nonce MUST be unique to prevent replay 234 attacks. It can be generated by appending a system clock to a 235 random number [RANDOM]. To verify the client's credentials, the 236 server preforms the following steps: 238 (a) Generate a buffer identical to step (E) above. 240 (b) Apply the HMAC-MD5 function with the stored client verifier as 241 the key and the result of (a) as the data. This produces a 16- 242 octet result equal to step (F) above. 244 (c) Exclusive-or the result of (b) with message (8) from the 245 client. This produces a 16-octet result which should be equal to 246 the result of step (C) above. 248 (d) Apply the MD5 function to the output of step (c). This 249 produces a 16-octet result which should be equal to the result of 250 step (D) above. 252 (e) if the result of (d) is equal to the stored verifier, then the 253 user is authenticated. 255 If no client challenge was provided in step (3), the server is now 256 done and responds with the appropriate status code. 258 (f) Generate a buffer identical to step (I) above. 260 (g) Apply the HMAC-MD5 function with the stored verifier as the key 261 and the buffer from (f) as the data. This produces a 16-octet 262 result. 264 The result of (g) is sent to the client to authenticate the server. 266 5. Example 268 The following is an example of the SCRAM-MD5 mechanism using the 269 IMAP [IMAP4] profile of SASL. Note that base64 encoding and the 270 lack of an initial client reponse with the first command are 271 characteristics of the IMAP profile of SASL and not characteristics 272 of SASL or SCRAM-MD5. 274 In this example, "C:" represents lines sent from the client to the 275 server and "S:" represents lines sent from the server to the 276 client. The wrapped lines are for editorial clarity -- there are 277 no actual newlines in the middle of the messages. 279 C: a001 AUTHENTICATE SCRAM-MD5 280 S: + 281 C: AGNocmlzADxwNVIxZTBWTzNLdFZBNEZITDdudWRRQGVsZWFub3Iua 282 W5ub3NvZnQuY29tPg== 283 S: AeYw5Ugm+blpbWFwQGVsZWFub3IuaW5ub3NvZnQuY29tAAA8b1JNa 284 nFFekYvL1J5WnhFMlF2cDNzd0BlbGVhbm9yLmlubm9zb2Z0LmNvbT4= 285 C: 5cZpsA9pODOVwuNU1xmJHA== 286 S: a001 OK [vJ1FEfRHulPALMwSb/UC9g==] AUTHENTICATE completed 288 For this example, the user "chris", with an empty authorization 289 identity is using the passphrase "secret stuff". The client nonce 290 is "" and the server 291 nonce is "". The 292 service identity is "imap@eleanor.innosoft.com" and the server 293 extension data is empty. The salt, in hexidecimal, is "01e6 30e5 294 4826 f9b9". The complete 40 octet verifier stored on the server, 295 in base64, is 296 "AeYw5Ugm+bkHTj2Ouau2II2etDOwYVEXkVsKPP0Q6pV9hbFaweymdg", and in 297 hexidecimal it is "01e6 30e5 4826 f9b9 074e 3d8e b9ab b620 8d9e 298 b433 b061 5117 915b 0a3c fd10 ea95 7d85 b15a c1ec a676". 300 6. Formal Syntax of SCRAM-MD5 Messages 302 This is the formal syntactic definition of the client and server 303 messages. This uses ABNF [ABNF] notation. 305 client-msg-1 = [authorize-id] NUL authenticate-id NUL [nonce] 306 ;; MUST NOT exceed 1000 octets 308 server-msg-1 = salt service-id NUL server-ext-data NUL nonce 309 ;; MUST NOT exceed 1000 octets 311 client-msg-2 = client-proof 313 server-msg-2 = server-proof 315 passphrase = *UTF8-SAFE 316 ;; At least 64 octets MUST be supported 318 authorize-id = *UTF8-PRINT 319 ;; No more than 255 octets 321 authenticate-id = *UTF8-PRINT 322 ;; No more than 255 octets 324 service-id = service-name "@" server-domain 326 service-name = *US-ASCII-PRINT 327 ;; a SASL/GSSAPI service name 329 server-domain = *US-ASCII-PRINT 330 ;; an internet domain name 332 server-ext-data = *(sasl-mech-list / tls-avail / ext-list) 334 sasl-mech-list = "SASL:" *(CFWS sasl-mech) CRLF 336 CFWS = [CRLF] 1*SPACE 338 sasl-mech = 1*20(ALPHA / DIGIT / "-" / "_") 340 tls-avail = "TLS:" SPACE "yes" 342 ext-list = 1*UTF8PRINT ":" *(CFWS 1*UTF8PRINT) CRLF 344 nonce = 8*OCTET 346 salt = 8OCTET 348 client-proof = 16OCTET 350 server-proof = 16OCTET 352 NUL = %x00 ;; US-ASCII NUL character 354 US-ASCII-SAFE = %x01-09 / %x0B-0C / %x0E-7F 355 ;; US-ASCII except CR, LF, NUL 357 US-ASCII-PRINT = %x20-7E 358 ;; printable US-ASCII including SPACE 360 UTF8-SAFE = US-ASCII-SAFE / UTF8-1 / UTF8-2 / UTF8-3 361 / UTF8-4 / UTF8-5 363 UTF8-PRINT = US-ASCII-PRINT / UTF8-1 / UTF8-2 / UTF8-3 364 / UTF8-4 / UTF8-5 366 UTF8-CONT = %x80..BF 368 UTF8-1 = %xC0..DF UTF8-CONT 370 UTF8-2 = %xE0..EF 2UTF8-CONT 372 UTF8-3 = %xF0..F7 3UTF8-CONT 374 UTF8-4 = %xF8..FB 4UTF8-CONT 376 UTF8-5 = %xFC..FD 5UTF8-CONT 378 7. System Administrator Advice 380 This section includes advice for system administrators using this 381 mechanism. 383 SCRAM stores three pieces of information for each user: a salt, a 384 client verifier and server key. The latter two are derived from 385 the salt and the user's passphrase. 387 The salt prevents global dictionary attacks, similar to the salt 388 used in Unix /etc/passwd files. As the 12 bits of salt in Unix 389 /etc/passwd has proved to be insufficient, SCRAM uses 64 bits of 390 salt. See [SCHNEIER] for a good discussion of salt and dictionary 391 attacks. In a multi-server site, security can be increased by 392 using a different salt on each server. 394 Although the verifiers used by SCRAM-MD5 have roughly comparable 395 security to those used by current plaintext mechanisms (such as 396 Unix /etc/passwd), it is still very important to keep them secret. 397 Just as tools exist to try common passwords against Unix 398 /etc/passwd files, it is also possible to build such tools for 399 SCRAM-MD5. In addition, once a SCRAM-MD5 verifier is stolen, a 400 passive (undetectable) evesdropper of that user logging in gains 401 the output of step (C) above, which is sufficient to impersonate 402 the user to all services with the same salt. This is far better 403 than current plaintext mechanisms where a passive evesdropper 404 always recovers the user's password, but is still a serious 405 concern. 407 Verifiers SHOULD be kept hidden from all users on the server. 408 Sites which distribute verifiers among multiple servers, SHOULD 409 encrypt them when distributing them. 411 SCRAM-MD5 is only a good mechanism if passphrases are well chosen. 412 For this reason, implementations should use the term "passphrase" 413 rather than "password" and when a user's passphrase is set, site 414 policy restrictions should be applied. A reasonable site policy 415 would require passphrases of at least 10 characters with at least 416 one non-alphanumeric character. 418 SCRAM-MD5 doesn't protect the integrity or privacy of data 419 exchanged after authentication. Use of TLS [TLS] or a stronger 420 SASL mechanism such as Kerberos is encouraged if this functionality 421 is needed. 423 8. SCRAM-MD5 Functional Notation 425 This section is designed to provide a quick understanding of 426 SCRAM-MD5 for those who like functional notation. 428 + octet concatenation 429 XOR the exclusive-or function 430 AU is the authentication user identity (NUL terminated) 431 AZ is the authorization user identity (NUL terminated) 432 if AZ is the same as AU, a single NUL is used instead. 433 service is the name of the service and server (NUL terminated) 434 ext-attr server extension attributes (NUL terminated) 435 pass is the plaintext passphrase 436 H(x) is a one-way hash function applied to "x", such as MD5 437 MAC(x,y) is a message authentication code (MAC) such as HMAC-MD5 438 "y" is the key and "x" is the text signed by the key. 439 salt is a per-user salt value the server stores 440 Us is a unique nonce the server sends to the client 441 Uc is a unique nonce the client sends to the server 443 The following computed values are used in the exchange: 445 client-chal = AZ + AU + Uc 446 server-chal = salt + service + ext-attr + Us 447 salted-pass = MAC(salt, pass) 448 client-key = H(salted-pass) 449 client-verifier = H(client-key) 450 shared-key = MAC(server-chal + client-chal, client-verifier) 451 client-proof = client-key XOR shared-key 452 server-key = MAC(salt, salted-pass) 453 server-proof = MAC(client-chal + server-chal, server-key) 455 The SCRAM exchange is as follows: 457 (1) client -> server: client-chal 458 (2) server -> client: server-chal 459 (3) client -> server: client-proof 460 (4) server -> client: server-proof 462 The server stores the salt, client-verifier and server-key. It 463 authenticates the client by computing: 465 H(client-proof XOR shared-key) 467 after step 3 and comparing it to the stored client-verifier. 469 The client verifies the server by computing the server-proof 470 directly and comparing. 472 9. Usage Scenarios 474 Single Sign-on 475 As with CRAM, the intermediate HMAC context from step (B) can 476 be used for a single sign-on client model. SCRAM also adds 477 the ability to store the output of step (B) for the single 478 sign-on only to services with the same salt. If expiration is 479 needed, it can be built into the single sign-on facility. 480 Kerberos is necessary if server-enforced expiration is needed. 481 OTP is necessary if expiration after a fixed number of 482 authentications is necessary. 484 Simplicity 485 CRAM, SCRAM and OTP are all suitable for use in lightweight 486 clients or servers. Kerberos and public key technology are 487 not simple enough. 489 Frequent Authentications 490 Protocols such as IMAP or POP result in frequent 491 authentications by the same user. OTP, by itself, is not 492 suitable for such services as the sequence needs to be reset. 493 OTP with OTP extended responses still does not permit 494 simulatanous connections by the same user. 496 Location Independent User 497 SCRAM, CRAM and OTP are all suitable for users which move 498 between many clients. Public key client authentication will 499 not be suitable for such uses until there is a worldwide smart 500 card standard. 502 Scalability / Server Efficiency 503 CRAM and SCRAM are believed to be scalable to large numbers of 504 users. OTP is less scalable due to the need to provide per- 505 user locking and update services to the authentication 506 database. 508 Client Efficiency 509 SCRAM has about half the client efficiency of CRAM. OTP's 510 client efficiency varies with the sequence number and it is 511 usually many times slower than SCRAM. Public key systems are 512 even slower. 514 Limited Server Trust 515 The server-key may be stored on a central SCRAM server which 516 limits the services an application server is permitted to 517 offer. CRAM and OTP do not offer this functionality. 519 Multi-Vendor Scenarios 520 SCRAM does not require cooperation between multiple services 521 on the same server or multiple applications on the same 522 client. This has proved to be a deployment problem for 523 Kerberos. 525 Proxy Authentication 526 SCRAM supports proxy authentication by including a separate 527 authentication and authorization identifiers. CRAM lacks this 528 facility. 530 10. Security Considerations 532 Security considerations are discussed throughout this document. 533 The security considerations of MD5 [MD5] and HMAC [HMAC] also 534 apply. SCRAM relies primarily on the one-way characteristic of MD5 535 and HMAC-MD5 for cryptographic security. 537 An analysis of different attacks follows: 539 Passive Network Attacks 541 SCRAM is resistant to replay attacks as long as the appropriate 542 nonce is unique. 544 SCRAM is not resistant to passive dictionary attacks. User 545 education, passphrase setting policy and TLS [TLS] may be used to 546 protect against such attacks. 548 SCRAM does not protect against session data evesdropping. TLS 549 [TLS] may be used to protect against this. 551 Active Network Attacks 553 SCRAM protects against server impersonation with the optional 554 server authentication. CRAM and OTP do not have this facility. 556 SCRAM can protect against client impersonation by providing no 557 information beyond the salt to a client which fails verification. 558 Note that in order to prevent revealing the existance of a user to 559 such attackers, the server will have to invent consistant salt 560 between attempts and fail after the second client message. One way 561 to do this would be to store a random secret and use 562 HMAC(user-name, random-secret) to generate consistant salt values. 564 The server-ext-data may be used to protect against downgrade active 565 attacks (where the active attacker changes the advertised protocol 566 security services). CRAM and OTP do not have this facility. 568 SCRAM protects against account hijacking by an active attacker. 569 Use of OTP extended response [OTP-EXT] to reset the sequence is 570 susceptible to account hijacking. 572 SCRAM does not protect against connection hijacking or corruption. 573 TLS [TLS] or IPAUTH [IPAUTH] may be used to protect against this. 575 SCRAM does not protect against active denial of service attacks. 577 Server Attacks 579 SCRAM verifiers by themselves can not be used to impersonate the 580 user. CRAM verifiers have this weakness. 582 An attacker which has access to both the SCRAM verifier and a 583 client exchange for a particular user gains the ability to 584 impersonate that user to other servers using the same salt. TLS 585 [TLS] can make it more difficult to obtain the client exchange, but 586 does not defend against installation of a trojan horse server. 588 Client Attacks 590 As SCRAM is designed for user entry of a plaintext passphrase, it 591 is vulnerable to passphrase hijacking by trojan horse clients. OTP 592 [OTP] with an independent OTP calculator can be used to limit the 593 vulnerability to a single session. 595 11. Intellectual Property Issues and Prior Art 597 The author is not aware of any patents which apply to this 598 mechanism. 600 This is primarily a derivative of simple hash-based challenge 601 response systems. The hash-based challenge response idea has 602 existed since at least 1992, when the RIPE project published the 603 SKID algorithm according to [SCHNEIER]. 605 The repeated-hash idea used to verify the client's authenticator is 606 derived from S/KEY [SKEY]. 608 The idea of using salt to protect against global dictionary attacks 609 dates back to at least the Unix /etc/password system. There is 610 some discussion of this in [SCHNEIER]. 612 SCRAM combines these techniques. The author of this specification 613 first proposed this on a public mailing list July 16, 1997. 615 12. References 617 [ABNF] Crocker, D., "Augmented BNF for Syntax Specifications: 618 ABNF", Work in progress: draft-ietf-drums-abnf-xx.txt 620 [CRAM-MD5] Klensin, Catoe, Krumviede, "IMAP/POP AUTHorize Extension 621 for Simple Challenge/Response", RFC 2195, MCI, September 1997. 623 625 [HMAC] Krawczyk, Bellare, Canetti, "HMAC: Keyed-Hashing for Message 626 Authentication", RFC 2104, IBM, UCSD, February 1997. 628 630 [IMAP4] Crispin, M., "Internet Message Access Protocol - Version 631 4rev1", RFC 2060, University of Washington, December 1996. 633 635 [IPAUTH] Atkinson, "IP Authentication Header", RFC 1826, Naval 636 Research Laboratory, August 1995. 638 640 [KEYWORDS] Bradner, "Key words for use in RFCs to Indicate 641 Requirement Levels", RFC 2119, Harvard University, March 1997. 643 645 [MD5] Rivest, "The MD5 Message Digest Algorithm", RFC 1321, MIT 646 Laboratory for Computer Science, April 1992. 648 650 [OTP] Haller, Metz, "A One-Time Password System", RFC 1938, 651 Bellcore, Kaman Sciences Corporation, May 1996. 653 655 [OTP-EXT] Metz, "OTP Extended Responses", work in progress. 657 [POP3] Myers, J., Rose, M., "Post Office Protocol - Version 3", RFC 658 1939, Carnegie Mellon, Dover Beach Consulting, Inc., May 1996. 660 662 [RANDOM] Eastlake, Crocker, Schiller, "Randomness Recommendations 663 for Security", RFC 1750, DEC, Cybercash, MIT, December 1994. 665 667 [SASL] Myers, "Simple Authentication and Security Layer (SASL)", 668 work in progress. 670 [SCHNEIER] Schneier, "Applied Cryptography: Protocols, Algorithms 671 and Source Code in C," John Wiley and Sons, Inc., 1996. 673 [SKEY] Haller, Neil M. "The S/Key One-Time Password System", RFC 674 1760, Bellcore, February 1995. 676 678 [TLS] Dierks, Allen, "The TLS Protocol Version 1.0", Work in 679 progress. 681 [UTF8] Yergeau, F. "UTF-8, a transformation format of Unicode and 682 ISO 10646", RFC 2044, Alis Technologies, October 1996. 684 686 13. Author's Address 688 Chris Newman 689 Innosoft International, Inc. 690 1050 Lakes Drive 691 West Covina, CA 91790 USA 693 Email: chris.newman@innosoft.com 695 A. Appendix - TWEKE Proposal 697 Tom Wu has proposed adding a Diffie-Hellman key exchange to this 698 mechanism. Diffie-Hellman works roughly as follows: 700 Server picks g, n and x. Server computes X = g^x mod n. 702 server -> client: g, n, X 704 Client picks y and computes Y = g^y mod n and K = X^y mod n. 706 client -> server: Y 708 Server computes K = Y^x mod n (which is the same as the client's 709 K). 711 If g, n, x and y are sufficiently big and have the right 712 characteristics, then both the client and server share K which is 713 very difficult for a passive evesdropper to obtain. 715 The TWEKE proposal would add the following steps: 717 (4.5) Server sends g, n, X. 719 (8.5) Client sends Y. 721 and would modify steps (F), (J), (b) and (g) to include the value 722 K. This would result in a protocol safe from passive network 723 attacks. The expense would be reduced performance, the need for a 724 bignum math library and possibly a requirement that an export 725 license be obtained from certain governments (included the United 726 States). This would not defend against active attacks unless an 727 encryption service was added. This may be free of patent 728 restrictions. 730 TWEKE would be harder to deploy than SCRAM due to the higher math, 731 the use of public key technology and the performance loss. 733 B. Appendix - Additional Services 735 Several additional services are needed to make SCRAM useful in 736 various usage scenarios. These include remote authentication 737 database support for servers, authentication database APIs for 738 servers, remote passphrase change support for clients, 739 single-sign-on APIs for clients and management tools. The 740 service-id and server-key are included to facilite the remote 741 authentication database service. Otherwise these issues are 742 deferred for future work. 744 C. Appendix - HMAC-MD5 Sample Source Code 746 The following sample C source code is calls the source code in 747 [MD5] and is derived from the source code in [HMAC]. It is needed 748 by the SCRAM source code in the next section. 750 /* hmac-md5.h -- HMAC-MD5 functions 751 */ 753 #define HMAC_MD5_SIZE 16 754 /* intermediate MD5 context */ 755 typedef struct HMAC_MD5_CTX_s { 756 MD5_CTX ictx, octx; 757 } HMAC_MD5_CTX; 759 /* One step hmac computation 760 * 761 * digest may be same as text or key 762 */ 763 void hmac_md5(const unsigned char *text, int text_len, 764 const unsigned char *key, int key_len, 765 unsigned char digest[HMAC_MD5_SIZE]); 767 /* create intermediate result from key 768 */ 769 void hmac_md5_init(HMAC_MD5_CTX *hmac, 770 const unsigned char *key, int key_len); 772 #define hmac_md5_update(hmac, text, text_len) \ 773 MD5Update(&(hmac)->ictx, (text), (text_len)) 775 /* finish hmac from intermediate result. 776 * Intermediate result is zeroed. 777 */ 778 void hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE], 779 HMAC_MD5_CTX *hmac); 781 /* hmac-md5.c -- Keyed-Hashing 782 * derived from RFC 2104 by H. Krawczyk, M. Bellare, R.Canetti 783 */ 785 #include 786 #include 787 #include "md5.h" 788 #include "hmac-md5.h" 790 /* MD5 block size */ 791 #define BLOCK_SIZE 64 793 void hmac_md5_init(HMAC_MD5_CTX *hmac, 794 const unsigned char *key, int key_len) 795 { 796 unsigned char k_pad[BLOCK_SIZE]; /* padded key */ 797 int i; 798 /* if key longer than BLOCK_SIZE bytes reset it to MD5(key) */ 799 if (key_len > BLOCK_SIZE) { 800 MD5Init(&hmac->ictx); 801 MD5Update(&hmac->ictx, key, key_len); 802 MD5Final(k_pad, &hmac->ictx); 803 key = k_pad; 804 key_len = HMAC_MD5_SIZE; 805 } 807 /* XOR padded key with inner pad value */ 808 for (i = 0; i < key_len; i++) { 809 k_pad[i] = key[i] ^ 0x36; 810 } 811 while (i < BLOCK_SIZE) { 812 k_pad[i++] = 0x36; 813 } 815 /* Begin inner MD5 */ 816 MD5Init(&hmac->ictx); 817 MD5Update(&hmac->ictx, k_pad, BLOCK_SIZE); 819 /* XOR padded key with outer pad value */ 820 for (i = 0; i < BLOCK_SIZE; ++i) { 821 k_pad[i] ^= (0x36 ^ 0x5c); 822 } 824 /* Begin outer MD5 */ 825 MD5Init(&hmac->octx); 826 MD5Update(&hmac->octx, k_pad, BLOCK_SIZE); 828 /* clean up workspace */ 829 memset(k_pad, 0, BLOCK_SIZE); 830 } 832 void hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE], 833 HMAC_MD5_CTX *hmac) 834 { 835 /* finish inner MD5 */ 836 MD5Final(digest, &hmac->ictx); 837 /* finish outer MD5 */ 838 MD5Update(&hmac->octx, digest, HMAC_MD5_SIZE); 839 MD5Final(digest, &hmac->octx); 840 /* MD5Final zeros context */ 841 } 843 void hmac_md5(const unsigned char *text, int text_len, 844 const unsigned char *key, int key_len, 845 unsigned char digest[HMAC_MD5_SIZE]) 847 { 848 HMAC_MD5_CTX hmac; 850 hmac_md5_init(&hmac, key, key_len); 851 hmac_md5_update(&hmac, text, text_len); 852 hmac_md5_final(digest, &hmac); 853 } 855 D. Appendix - SCRAM sample source code 857 The following sample source code implements SCRAM itself for both 858 server and client. 860 Please note the comments marked "/*XXX ... */" as they need to be 861 translated from English to computer readable code. 863 A client implementation simply calls scram_md5_generate() with the 864 passphrase after receiving the first server reply. The cproof 865 parameter will hold the message to send to the server and the 866 sproof parameter will hold the expected server mutual 867 authentication. A client may also call cram_md5_cred() to turn a 868 passphrase into CRAM/SCRAM credentials for later use in 869 scram_md5_generate(). 871 A server implementation simply calls scram_md5_generate() with the 872 stored verifier, the second client message and the SCRAM_VERIFY 873 option. Server verifiers are generated by creating a random salt 874 and calling scram_md5_vgen() with either the passphrase or 875 CRAM/SCRAM credentials. 877 /* scram.h -- scram utility functions 878 */ 880 /* size of CRAM_MD5 verifier and CRAM_MD5/SCRAM_MD5 credentials */ 881 #define CRAM_MD5_SIZE 32 883 /* size of SCRAM_MD5 salt and verifier */ 884 #define SCRAM_MD5_SALTSIZE 8 885 #define SCRAM_MD5_DATASIZE 16 887 /* SCRAM verifier */ 888 typedef struct SCRAM_MD5_VRFY_s { 889 unsigned char salt[SCRAM_MD5_SALTSIZE]; 890 unsigned char clidata[SCRAM_MD5_DATASIZE]; 891 unsigned char svrdata[SCRAM_MD5_DATASIZE]; 892 } SCRAM_MD5_VRFY; 893 /* prepare CRAM-MD5 credentials/verifier also SCRAM-MD5 credential 894 * buf -- must be aligned and have room for CRAM_MD5_SIZE 895 * pass -- passphrase or verifier 896 * passlen -- len of pass/verifier (0 ok if NUL terminated) 897 */ 898 void cram_md5_cred(char *buf, const char *pass, int passlen); 900 /* generate SCRAM-MD5 verifier 901 * vptr -- gets result 902 * salt -- contains salt of SCRAM_MD5_SALTSIZE 903 * pass -- passphrase or verifier 904 * passlen -- len of pass/verifier (0 ok if NUL terminated) 905 * plainflag -- 1 = plaintext passphrase, 906 * 0 = result of cram_md5_cred() 907 * clientkey -- cache for client proof, usually NULL 908 */ 909 void scram_md5_vgen(SCRAM_MD5_VRFY *vptr, 910 const unsigned char *salt, 911 const char *pass, int passlen, int plainflag, 912 unsigned char *clientkey); 914 /* scram secret action type 915 */ 916 #define SCRAM_CREDENTIAL 0 /* generate replies using credentials */ 917 #define SCRAM_PLAINTEXT 1 /* generate replies using plaintext */ 918 #define SCRAM_VERIFY 2 /* use SCRAM_MD5_VRFY to verify client, 919 and generate server reply */ 921 /* generate or verify SCRAM-MD5 922 * input params: 923 * cchal -- client challenge string 924 * cchallen -- length of client challenge 925 * schal -- server challenge string 926 * schallen -- length of server challenge 927 * secret -- passphrase, credentials or verifier 928 * secretlen -- length of passphrase (0 ok if NUL terminated) 929 * action -- see above 930 * in/out: 931 * cproof -- client proof of length SCRAM_MD5_DATASIZE 932 * output: 933 * sproof -- server proof of length SCRAM_MD5_DATASIZE 934 * returns: 935 * -2 if params invalid 936 * -1 if verify fails 937 * 0 on success 938 */ 939 int scram_md5_generate(const char *cchal, int cchallen, 940 const char *schal, int schallen, 941 const char *secret, int secretlen, 942 int action, unsigned char *cproof, 943 unsigned char *sproof); 945 /* scram.c -- routines for SCRAM-MD5 calculations 946 */ 948 #include 949 #include 950 #include 951 #include "md5.h" 952 #include "hmac-md5.h" 953 #include "scram.h" 955 /* for htonl() and ntohl() */ 956 #include 957 #include 959 /* MD5 block size */ 960 #define BLOCK_SIZE 64 962 /* intermediate CRAM context 963 * values stored in network byte order (Big Endian) 964 */ 965 typedef struct CRAM_MD5_CTX_s { 966 UINT4 istate[4]; 967 UINT4 ostate[4]; 968 } CRAM_MD5_CTX; 970 void cram_md5_cred(char *buf, const char *pass, int passlen) 971 { 972 HMAC_MD5_CTX hctx; 973 CRAM_MD5_CTX *ctx = (CRAM_MD5_CTX *) buf; 975 if (passlen == 0) passlen = strlen(pass); 976 hmac_md5_init(&hctx, (const unsigned char *) pass, passlen); 977 ctx->istate[0] = htonl(hctx.ictx.state[0]); 978 ctx->istate[1] = htonl(hctx.ictx.state[1]); 979 ctx->istate[2] = htonl(hctx.ictx.state[2]); 980 ctx->istate[3] = htonl(hctx.ictx.state[3]); 981 ctx->ostate[0] = htonl(hctx.octx.state[0]); 982 ctx->ostate[1] = htonl(hctx.octx.state[1]); 983 ctx->ostate[2] = htonl(hctx.octx.state[2]); 984 ctx->ostate[3] = htonl(hctx.octx.state[3]); 985 memset(&hctx, 0, sizeof (hctx)); 986 } 987 /* extract hmac context from CRAM-MD5 credentials 988 */ 989 void hmac_cram_md5_init(HMAC_MD5_CTX *hctx, CRAM_MD5_CTX *ctx) 990 { 991 hctx->ictx.state[0] = ntohl(ctx->istate[0]); 992 hctx->ictx.state[1] = ntohl(ctx->istate[1]); 993 hctx->ictx.state[2] = ntohl(ctx->istate[2]); 994 hctx->ictx.state[3] = ntohl(ctx->istate[3]); 995 hctx->octx.state[0] = ntohl(ctx->ostate[0]); 996 hctx->octx.state[1] = ntohl(ctx->ostate[1]); 997 hctx->octx.state[2] = ntohl(ctx->ostate[2]); 998 hctx->octx.state[3] = ntohl(ctx->ostate[3]); 999 hctx->ictx.count[0] = hctx->octx.count[0] = BLOCK_SIZE << 3; 1000 hctx->ictx.count[1] = hctx->octx.count[1] = 0; 1001 } 1003 void scram_md5_vgen(SCRAM_MD5_VRFY *vptr, 1004 const unsigned char *salt, 1005 const char *pass, int passlen, int plainflag, 1006 unsigned char *clientkey) 1007 { 1008 HMAC_MD5_CTX hctx; 1010 if (clientkey == NULL) clientkey = vptr->clidata; 1012 /* get context */ 1013 if (plainflag) { 1014 if (passlen == 0) passlen = strlen(pass); 1015 hmac_md5_init(&hctx, (const unsigned char *) pass, 1016 passlen); 1017 } else { 1018 hmac_cram_md5_init(&hctx, (CRAM_MD5_CTX *) pass); 1019 } 1021 /* generate salted passphrase */ 1022 hmac_md5_update(&hctx, salt, SCRAM_MD5_SALTSIZE); 1023 hmac_md5_final(vptr->clidata, &hctx); 1025 /* generate server proof */ 1026 hmac_md5(salt, SCRAM_MD5_SALTSIZE, vptr->clidata, 1027 sizeof (vptr->clidata), vptr->svrdata); 1029 /* generate client key and client verifier */ 1030 MD5Init(&hctx.ictx); 1031 MD5Update(&hctx.ictx, vptr->clidata, sizeof (vptr->clidata)); 1032 MD5Final(clientkey, &hctx.ictx); 1033 MD5Init(&hctx.ictx); 1034 MD5Update(&hctx.ictx, clientkey, SCRAM_MD5_DATASIZE); 1035 MD5Final(vptr->clidata, &hctx.ictx); 1037 /* copy salt to verifier */ 1038 if (salt != vptr->salt) { 1039 memcpy(vptr->salt, salt, SCRAM_MD5_SALTSIZE); 1040 } 1041 } 1043 int scram_md5_generate(const char *cchal, int cchallen, 1044 const char *schal, int schallen, 1045 const char *secret, int secretlen, 1046 int action, unsigned char *cproof, 1047 unsigned char *sproof) 1048 { 1049 SCRAM_MD5_VRFY verifier, *vptr; 1050 HMAC_MD5_CTX hctx; 1051 unsigned char clientkey[HMAC_MD5_SIZE]; 1052 unsigned char sharedkey[HMAC_MD5_SIZE]; 1053 int i, result = 0; 1055 /* check params */ 1056 if ((action == SCRAM_CREDENTIAL && secretlen != CRAM_MD5_SIZE) 1057 || (action == SCRAM_VERIFY 1058 && secretlen != sizeof (verifier)) 1059 || schallen < SCRAM_MD5_SALTSIZE) { 1060 return (-2); 1061 } 1063 /* get verifier */ 1064 if (action == SCRAM_VERIFY) { 1065 vptr = (SCRAM_MD5_VRFY *) secret; 1066 } else { 1067 scram_md5_vgen(&verifier, (const unsigned char *) schal, 1068 secret, secretlen, action, clientkey); 1069 vptr = &verifier; 1070 } 1072 /* calculate shared key */ 1073 hmac_md5_init(&hctx, vptr->clidata, sizeof (vptr->clidata)); 1074 hmac_md5_update(&hctx, (unsigned char *) schal, schallen); 1075 hmac_md5_update(&hctx, (unsigned char *) cchal, cchallen); 1076 hmac_md5_final(sharedkey, &hctx); 1078 if (action == SCRAM_VERIFY) { 1079 /* verify client proof */ 1080 for (i = 0; i < HMAC_MD5_SIZE; ++i) { 1081 /*XXX: the line which belongs here is omitted due to U.S. 1082 export regulations, but it exclusive-ors the 1083 "sharedkey" with the "cproof" and places the result in 1084 "clientkey" (see step (c) above) */ 1085 } 1086 MD5Init(&hctx.ictx); 1087 MD5Update(&hctx.ictx, clientkey, sizeof (clientkey)); 1088 MD5Final(clientkey, &hctx.ictx); 1089 if (memcmp(clientkey, vptr->clidata, 1090 sizeof (clientkey)) != 0) { 1091 result = -1; 1092 } 1093 } else { 1094 /* generate client proof */ 1095 for (i = 0; i < HMAC_MD5_SIZE; ++i) { 1096 /*XXX: the line which belongs here is omitted due to U.S. 1097 export regulations, but it exclusive-ors the 1098 "sharedkey" with the "clientkey" and places the result 1099 in "cproof" (see step (G) above) */ 1100 } 1101 } 1103 /* calculate server result */ 1104 if (result == 0) { 1105 hmac_md5_init(&hctx, vptr->svrdata, HMAC_MD5_SIZE); 1106 hmac_md5_update(&hctx, (unsigned char *) schal, schallen); 1107 hmac_md5_update(&hctx, (unsigned char *) cchal, cchallen); 1108 hmac_md5_final(sproof, &hctx); 1109 } 1111 /* cleanup workspace */ 1112 memset(clientkey, 0, sizeof (clientkey)); 1113 memset(sharedkey, 0, sizeof (sharedkey)); 1114 if (vptr == &verifier) memset(&verifier, 0, sizeof (verifier)); 1116 return (result); 1117 }