idnits 2.17.1 draft-newman-auth-scram-03.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-19) 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 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. ** The abstract seems to contain references ([CRAM-MD5], [OTP], [SASL]), which it shouldn't. Please replace those with straight textual mentions of the documents in question. Miscellaneous warnings: ---------------------------------------------------------------------------- == Line 540 has weird spacing: '...secinfo clien...' == Line 541 has weird spacing: '...secinfo serve...' == Line 542 has weird spacing: '...service is t...' == 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 (March 1998) is 9532 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 721, but not defined -- Looks like a reference, but probably isn't: '01000000' on line 407 -- Looks like a reference, but probably isn't: '00' on line 407 == Missing Reference: 'SCRAM-MD5' is mentioned on line 816, but not defined -- Looks like a reference, but probably isn't: '4' on line 1018 -- Looks like a reference, but probably isn't: '0' on line 971 -- Looks like a reference, but probably isn't: '1' on line 972 -- Looks like a reference, but probably isn't: '2' on line 969 -- Looks like a reference, but probably isn't: '3' on line 970 == Unused Reference: 'OTP-EXT' is defined on line 765, but no explicit reference was found in the text == Unused Reference: 'UTF8' is defined on line 786, but no explicit reference was found in the text ** Obsolete normative reference: RFC 2234 (ref. 'ABNF') (Obsoleted by RFC 4234) -- Possible downref: Non-RFC (?) normative reference: ref. 'CERT-IPSPOOF' ** Obsolete normative reference: RFC 2065 (ref. 'DNSSEC') (Obsoleted by RFC 2535) ** 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) ** Obsolete normative reference: RFC 1827 (ref. 'IPESP') (Obsoleted by RFC 2406) ** Downref: Normative reference to an Informational RFC: RFC 1321 (ref. 'MD5') ** Obsolete normative reference: RFC 1938 (ref. 'OTP') (Obsoleted by RFC 2289) ** Obsolete normative reference: RFC 1750 (ref. 'RANDOM') (Obsoleted by RFC 4086) ** Obsolete normative reference: RFC 2222 (ref. 'SASL') (Obsoleted by RFC 4422, RFC 4752) -- 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 2279 (ref. 'UTF8') (Obsoleted by RFC 3629) Summary: 21 errors (**), 0 flaws (~~), 9 warnings (==), 13 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-03.txt March 1998 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 SASL [SASL] authentication 31 mechanism suitable for a wide variety of usage scenarios. It 32 combines good properties of CRAM-MD5 [CRAM-MD5] and OTP [OTP], adds 33 some management features and some protection from active attacks 34 without a significant increase in complexity. SCRAM is intended 35 for use with services which need a simple, fast and flexible 36 authentication mechanism. 38 [NOTE: Public discussion of this mechanism may take place on the 39 ietf-sasl@imc.org mailing list with a subscription address of 40 ietf-sasl-request@imc.org. Private comments may be sent to the 41 author]. 43 1. How to Read This Document 45 This document has information for several different audiences. 47 Section 2 provides an introduction to SCRAM. Sections 3-6 and 9 48 are intended for implementors. Section 7 is intended for system 49 administrators. Sections 7-10 are intended for security 50 evaluation. 52 The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT" and "MAY" 53 in this document are to be interpreted as defined in "Key words for 54 use in RFCs to Indicate Requirement Levels" [KEYWORDS]. 56 2. Introduction 58 This section describes the design goals, an overview of how SCRAM 59 operates and the intended use of SCRAM in comparison to OTP. 61 2.1. Design Goals 63 The perfect authentication mechanism would be simple, fast, strong, 64 use publicly available source code and be backwards compatible with 65 deployed back-end authentication databases. It is impossible to 66 achieve all these goals so tradeoffs must be made. SCRAM has 67 simplicity, speed and protection from passive and active attacks on 68 the connection (with the exception of dictionary attacks) as 69 primary design goals. It has managability, backwards compatibility 70 with CRAM-MD5 intermediate HMAC state verifiers, some protection 71 from a compromised authentication database and publicly 72 distributable source code as secondary design goals. 74 SCRAM has the following characteristics: 76 o It is a simple passphrase-based mechanism which does not require 77 complicated infrastructures or public key technology. The 78 majority of the source code necessary to implement SCRAM is 79 included in the MD5 specification [MD5] and Appendices B and C 80 of this specification. 82 o It does not require plain-text-equivalent verifiers on the 83 server, so it improves network security over traditional 84 plain-text password systems without eliminating security of the 85 server authentication database. 87 o It supports proxy authentication by including an authorization 88 identity (user to login as) separate from the authentication 89 identity (server authentication database entry to use). 91 o It supports mutual authentication. 93 o It supports a limited service trust management model. This 94 means a centralized authentication server could restrict the 95 services offered by application servers. 97 o It is backwards-compatible with CRAM-MD5 server authentication 98 databases. 100 o It includes an optional SASL integrity protection layer for 101 lightweight protection from many active attacks. 103 2.2. Basic Operation of SCRAM 105 SCRAM is built using only a simple one-way hash function, the HMAC 106 [HMAC] construction and the exclusive-or operation. There are 107 three fundamental components to the exchange: 109 o the client key which is derived from the passphrase and salt 111 o the client verifier which is simply the one-way hash function 112 applied to the client key 114 o the server key which is also derived from the passphrase and 115 salt 117 The server has access to the salt, client verifier and server key 118 for each user. The salt and client verifier are used to 119 authenticate the client to the server and the salt and server key 120 are used to authenticate the server to the client. 122 The mechanism relies on the one-way characteristic of the hash 123 function to assure that the client key can't be derived from the 124 client verifier and that the server key can't be derived from 125 either the client key or client verifier. 127 SCRAM uses HMAC to sign client and server nonces with the client 128 verifier to produce a shared key. The client exclusive-ors the 129 shared key with the client key and sends that to the server which 130 uses the shared key to reverse the exclusive-or operation, extract 131 the client key, and then verify that the hash function applied to 132 the client key matches the client verifier. The server uses HMAC 133 to sign the client and server nonces with the server key and sends 134 that to the client to authenticate. 136 2.3. Intended Use 138 SCRAM is designed for a usage scenario where simplicity and/or 139 speed is important, frequent authentications may occur and the 140 primary threat is passive and active network attacks. A good 141 example of protocols whose usage and threat model fit SCRAM are 142 IMAP [IMAP4] and POP3 [POP3]. SCRAM provides limited protection 143 against threats to the server authentication database, but OTP 144 [OTP] may be preferable for usage scenarios where the threat to the 145 server is more serious and active attacks are not an issue. 147 3. Client Implementation of SCRAM-MD5 149 This section includes a step-by-step guide for client implementors. 150 Section 6 contains the formal definition of the syntax and is the 151 authoritative reference in case of errors here. 153 When used with SASL the mechanism name is "SCRAM-MD5". The 154 mechanism does not provide a privacy layer, but does include an 155 optional integrity protection layer. 157 The client begins by sending a message to the server containing the 158 following three pieces of information. 160 (1) An authorization identity. When the empty string is used, this 161 defaults to the authentication identity. This is used by system 162 administrators or proxy servers to login with a different user 163 identity. This field may be up to 255 octets and is terminated by 164 a NUL (0) octet. US-ASCII printable characters are preferred, 165 although UTF-8 [UTF-8] printable characters are permitted to 166 support international names. Use of character sets other than 167 US-ASCII and UTF-8 is forbidden. 169 (2) An authentication identity. The identity whose passphrase will 170 be used. This field may be up to 255 octets and is terminated by a 171 NUL (0) octet. US-ASCII printable characters are preferred, 172 although UTF-8 [UTF-8] printable characters are permitted to 173 support international names. Use of character sets other than 174 US-ASCII and UTF-8 is forbidden. 176 (3) A "client nonce." It is important that this be globally 177 unique. One common technique for generating globally unique 178 identifiers combines a process identifier with the system clock, a 179 sequence number, a random number and the client's domain name. The 180 random number is important as clocks are often synchronized using 181 insecure protocols and are predictable. Advice for generating good 182 random numbers can be found in [RANDOM]. 184 The server responds by sending a message containing three pieces of 185 information: 187 (4) An 8-octet salt value, specific to the authentication identity. 189 (5) A one-octet bit-mask specifying security layers supported by 190 the server. Bit 0 (value 1) indicates support for no security 191 layer and bit 1 (value 2) indicates support for an integrity 192 protection layer. The other bits are reserved for future use (the 193 server MUST set them to zero until they are defined in a standards 194 track specification). If the client doesn't support a security 195 layer and bit 0 is cleared, then the authentication immediately 196 fails. 198 (6) A three-octet number in network byte order (big endian), 199 containing the maximum cipher-text buffer size the server is able 200 to receive. This may be 0 if the server supports no security 201 layers. 203 (7) A service id consisting of the service name of the protocol's 204 SASL profile followed by an "@" followed by the domain name of the 205 server and terminated by NUL. The client SHOULD verify this is 206 correct. 208 (8) A "server nonce". As the domain name is included in (7), this 209 only has to be unique to the server. 211 The client then does the following: 213 (A) Create a buffer containing the user's passphrase. The client 214 MUST support passphrases of at least 64 octets. US-ASCII 215 characters are preferred, although UTF-8 characters are permitted. 216 Character sets other than US-ASCII and UTF-8 MUST NOT be used. 218 (B) Apply the HMAC-MD5 function with (A) as the key and the 8-octet 219 salt as the data, producing a 16-octet result. Once this is done, 220 (A) SHOULD be erased from memory. 222 (C) Apply the MD5 function to the result of (B). This produces a 223 16-octet result. 225 (D) Apply the MD5 function to the result of (C). This produces a 226 16-octet result. 228 (E) Create a buffer containing the server's response (4)-(8), 229 immediately followed by the initial client message (1)-(3) and the 230 client's security layer selection (9)-(10) below. 232 (F) Apply the HMAC-MD5 function with the result of (D) as the key 233 and the buffer from (E) as the data. This produces a 16-octet 234 result. 236 (G) Create a 16-octet buffer containing the exclusive-or of (C) and 237 (F). 239 The client then sends a message to the server containing the 240 following: 242 (9) A bit-mask indicating the client selected security layer from 243 step (5). This has a value of 01 for no security layer and 02 for 244 an integrity protection layer. 246 (10) A three octet number indicating the maximum cipher-text buffer 247 size the client is able to receive in network byte order. If the 248 client doesn't select a security layer, this may be all zeros. 250 (11) The 16-octet result of step (G). 252 The server will respond with: 254 (12) A 16-octet server authentication verifier. 256 The client SHOULD verify this with the following procedure: 258 (H) Apply the HMAC-MD5 function with the result of (B) as the key 259 and the 8-octet salt as the data. This produces a 16-octet result. 261 (I) Create a buffer containing the initial client message (1)-(3) 262 immediately followed by the initial server response (4)-(8) and the 263 client's security layer selection (9)-(10). 265 (J) Apply the HMAC-MD5 function with the result of (H) as the key 266 and the buffer from (I) as the data. 268 (K) If the result of (J) matches (12), the server is authenticated. 270 A secured client MAY store the result of (B) to re-authenticate to 271 services using the same salt, or the intermediate HMAC state from 272 (B) to re-authenticate to any service. Clients SHOULD NOT store 273 the passphrase itself. 275 If integrity protection is negotiated on, the following procedure 276 is applied to each SASL security layer packet sent by the client: 278 (L) Apply the HMAC-MD5 function with the output of step (C) as the 279 key and the buffer from step (E) as the value. 281 (M) A buffer is created containing a four octet client packet 282 number in network byte order followed by the 16-octet output of 283 step (L). The first packet sent under the SASL security layer is 284 given number 1. 286 (N) Apply the HMAC-MD5 function with (M) as the key and the 287 contents of the packet as the data. The result is appended to the 288 end of the packet. 290 The integrity protection on packets from the server is verified as 291 follows: 293 (O) A buffer is created containing a four octet server packet 294 number in network byte order followed by the 16-octet output of 295 step (L) above. This first packet sent under the SASL security 296 layer is given number 1. 298 (P) Apply the HMAC-MD5 function with (O) as the key and all but the 299 last 16 octets of the packet as the value. 301 (Q) Compare the last 16 octets of the packet to the output of (P). 302 If they do not match, an integrity error is produced. 304 4. Server Implementation of SCRAM-MD5 306 The section includes a step-by-step guide for server implementors 307 building on the previous section. Section 6 contains the formal 308 definition of the syntax and is the authoritative reference in case 309 of errors here. 311 The server's authentication database contains an 8-octet salt, 312 16-octet client verifier and a 16-octet server key for each local 313 user. The server MUST support "user@host" syntax for the 314 authentication identity at least to the extent of stripping "@host" 315 when it matches the local host name or rejecting the authentication 316 if the host name doesn't match. The server MAY support remote user 317 authentication using this syntax. 319 The stored client verifier is equal to the result of step (D) 320 above, and the stored server key is equal to the result of step (H) 321 above. To create its initial response, the server simply looks up 322 the authentication identity to fetch the salt, and generates an 8 323 to 248 octet nonce. This nonce MUST be unique for the server to 324 prevent replay attacks. It can be generated by appending a system 325 clock to a process and/or thread identifier and a random number 326 [RANDOM]. To verify the client's credentials, the server performs 327 the following steps: 329 (a) Generate a buffer identical to step (E) above. 331 (b) Apply the HMAC-MD5 function with the stored client verifier as 332 the key and the result of (a) as the data. This produces a 333 16-octet result equal to step (F) above. 335 (c) Exclusive-or the result of (b) with message (11) from the 336 client. This produces a 16-octet result which should be equal to 337 the result of step (C) above. 339 (d) Apply the MD5 function to the output of step (c). This 340 produces a 16-octet result which should be equal to the result of 341 step (D) above. 343 (e) if the result of (d) is equal to the stored verifier, then the 344 user is authenticated. 346 If no client challenge was provided in step (3), the server is now 347 done and responds with the appropriate status code. Otherwise the 348 server continues as follows: 350 (f) Generate a buffer identical to step (I) above. 352 (g) Apply the HMAC-MD5 function with the stored server verifier as 353 the key and the buffer from (f) as the data. This produces a 354 16-octet result. 356 The result of (g) is sent to the client to authenticate the server. 358 If integrity protection is negotiated on, the integrity key is 359 computed as follows: 361 (h) Apply the HMAC-MD5 function with the output of step (c) as the 362 key and the buffer from step (a) as the data. 364 Integrity generation and verification works in the same fashion as 365 the client. 367 5. Example 369 In these examples, "C:" represents lines sent from the client to 370 the server and "S:" represents lines sent from the server to the 371 client. The wrapped lines are for editorial clarity -- there are 372 no actual newlines in the middle of the messages. 374 The following is an example of the SCRAM-MD5 mechanism using the 375 IMAP [IMAP4] profile of SASL. For this example, the user "chris", 376 with an empty authorization identity is using the passphrase 377 "secret stuff". The client nonce is 378 "" and the server 379 nonce is "jhcNZlRuPbziFp+vLV+NCw". No security layer is supported, 380 the salt is "testsalt" and the service identity is 381 "imap@eleanor.innosoft.com". The complete 40 octet verifier stored 382 on the server, in hexadecimal is "74657374 73616c74 16484d56 383 7ee02f47 ac5f8a5a d5795570 90d55334 d2002df6 24cb8c8b 75708f4e." 385 C: a001 AUTHENTICATE SCRAM-MD5 386 S: + 387 C: AGNocmlzADx0NG40UGFiOUhCMEFtL1FMWEI3MmVnQGVsZWFub3IuaW 388 5ub3NvZnQuY29tPg== 389 S: + dGVzdHNhbHQBAAAAaW1hcEBlbGVhbm9yLmlubm9zb2Z0LmNvbQBq 390 aGNOWmxSdVBiemlGcCt2TFYrTkN3 391 C: AQAAAMg9jU8CeB4KOfk7sUhSQPs= 392 S: + U0odqYw3B7XIIW0oSz65OQ== 393 C: 394 S: a001 OK AUTHENTICATE completed 396 Note that base64 encoding and the lack of an initial client 397 response with the first command are characteristics of the IMAP 398 profile of SASL and not characteristics of SASL or SCRAM-MD5. Here 399 is another example using the ACAP [ACAP] profile of SASL. This 400 uses the same salt, passphrase and verifier as the previous 401 example. In this example, binary data is represented as 402 hexadecimal digits enclosed in square brackets: 404 C: a001 AUTHENTICATE "SCRAM-MD5" {52} 405 C: [00]chris[00] 406 S: + {60} 407 S: testsalt[01000000]acap@eleanor.innosoft.com[00] 408 m6HdEYWZA5W8keNbiY40aA 409 C: {20} 410 C: [01000000 19b66406 4ce8138a e0af7b0b f0ed20ea] 411 S: a001 OK (SASL {16} 412 S: [44d7c1c4 0630fea6 5c49cb40 717a2ba5]) "Successful" 414 Note that arbitrary binary values may be used for the salt and 415 nonces, as long as the client nonce is globally unique. 417 6. Formal Syntax of SCRAM-MD5 Messages 419 This is the formal syntactic definition of the client and server 420 messages. This uses ABNF [ABNF] notation including the core rules. 422 client-msg-1 = [authorize-id] NUL authenticate-id NUL nonce 424 server-msg-1 = salt security-info service-id NUL nonce 425 client-msg-2 = security-info client-proof 427 server-msg-2 = server-proof 429 passphrase = *UTF8-SAFE 430 ;; At least 64 octets MUST be supported 432 authorize-id = *UTF8-PRINT 433 ;; No more than 255 octets 435 authenticate-id = *UTF8-PRINT 436 ;; No more than 255 octets 438 security-info = secbits bufsize 440 bufsize = 3OCTET 441 ;; in network byte order (big-endian) 443 secbits = OCTET 444 ;; bit 0 = no protection, bit 1 = integrity, 445 ;; other bits set to 0 and reserved 447 service-id = service-name "@" server-domain 449 service-name = *VCHAR 450 ;; a SASL/GSSAPI service name 452 server-domain = *VCHAR 453 ;; an internet domain name 455 nonce = 8*OCTET 457 salt = 8OCTET 459 client-proof = 16OCTET 461 server-proof = 16OCTET 463 NUL = %x00 ;; US-ASCII NUL character 465 UTF8-SAFE = %x01-09 / %x0B-0C / %x0E-7F / UTF8-MULTI 466 ;; Any character except CR, LF, NUL 468 UTF8-PRINT = %x20-7E / UTF8-MULTI 469 ;; Any character except CTLs 471 UTF8-MULTI = UTF8-2 / UTF8-3 / UTF8-4 / UTF8-5 / UTF8-6 472 ;; UTF-8 Multi-octet characters 474 UTF8-1 = %x80-BF 476 UTF8-2 = %xC0-DF UTF8-1 478 UTF8-3 = %xE0-EF 2UTF8-1 480 UTF8-4 = %xF0-F7 3UTF8-1 482 UTF8-5 = %xF8-FB 4UTF8-1 484 UTF8-6 = %xFC-FD 5UTF8-1 486 7. System Administrator Advice 488 This section includes advice for system administrators using this 489 mechanism. 491 A SCRAM server stores three pieces of information for each user: a 492 salt, a client verifier and server key. The latter two are derived 493 from the salt and the user's passphrase. 495 The salt prevents global dictionary attacks, similar to the salt 496 used in Unix /etc/passwd files. As the 12 bits of salt in Unix 497 /etc/passwd has proved to be insufficient, SCRAM uses 64 bits of 498 salt. See [SCHNEIER] for a good discussion of salt and dictionary 499 attacks. In a multi-server site, security can be increased by 500 using a different salt on each server. 502 Although the verifiers used by SCRAM-MD5 have roughly comparable 503 security to those used by current plain-text mechanisms (such as 504 Unix /etc/passwd), it is still very important to keep them secret. 505 Just as tools exist to try common passwords against Unix 506 /etc/passwd files, it is also possible to build such tools for 507 SCRAM-MD5. In addition, once a SCRAM-MD5 verifier is stolen, a 508 passive (undetectable) eavesdropper of that user logging in gains 509 the output of step (C) above, which is sufficient to impersonate 510 the user to all services with the same salt. This is better than 511 current plain-text mechanisms where a passive eavesdropper always 512 recovers the user's password, but is still a serious concern. 514 Verifiers SHOULD be kept hidden from all users on the server. 515 Sites which distribute verifiers among multiple servers, SHOULD 516 encrypt them when transferring them over the network. 518 SCRAM-MD5 is only a good mechanism if passphrases are well chosen. 519 For this reason, implementations should use the term "passphrase" 520 rather than "password" and when a user's passphrase is set, site 521 policy restrictions should be applied. A reasonably secure site 522 policy would require passphrases of at least 10 characters with at 523 least one non-alphanumeric character. 525 SCRAM-MD5 doesn't protect the privacy of data exchanged after 526 authentication. Use of TLS [TLS], IP security ESP [IPESP] or a 527 stronger SASL mechanism such as Kerberos is encouraged if this 528 functionality is needed. 530 8. SCRAM Functional Notation 532 This section is designed to provide a quick understanding of SCRAM 533 for those who like functional notation. 535 + octet concatenation 536 XOR the exclusive-or function 537 AU is the authentication user identity (NUL terminated) 538 AZ is the authorization user identity (NUL terminated) 539 if AZ is the same as AU, a single NUL is used instead. 540 csecinfo client security layer option bits and buffer size 541 ssecinfo server security layer option bits and buffer size 542 service is the name of the service and server (NUL terminated) 543 pass is the plain-text passphrase 544 H(x) is a one-way hash function applied to "x", such as MD5 545 MAC(x,y) is a message authentication code (MAC) such as HMAC-MD5 546 "y" is the key and "x" is the text signed by the key. 547 salt is a per-user salt value the server stores 548 Us is a unique nonce the server sends to the client 549 Uc is a unique nonce the client sends to the server 551 The SCRAM computations and exchange are as follows: 553 client-msg-1 = AZ + AU + Uc 554 (1) client -> server: client-msg-1 555 server-msg-1 = salt + ssecinfo + service + Us 556 (2) server -> client: server-msg-1 557 salted-pass = MAC(salt, pass) 558 client-key = H(salted-pass) 559 client-verifier = H(client-key) 560 shared-key = MAC(server-msg-1 + client-msg-1 + csecinfo, 561 client-verifier) 562 client-proof = client-key XOR shared-key 563 (3) client -> server: csecinfo + client-proof 564 server-key = MAC(salt, salted-pass) 565 server-proof = MAC(client-msg-1 + server-msg-1 + csecinfo, 566 server-key) 567 (4) server -> client: server-proof 568 integrity-key = MAC(server-msg-1 + client-msg-1 + csecinfo, 569 client-key) 571 The server stores the salt, client-verifier and server-key. It 572 authenticates the client by computing: 574 H(client-proof XOR shared-key) 576 after step 3 and comparing it to the stored client-verifier. The 577 server computes the integrity-key with: 579 MAC(server-msg-1 + client-msg-1, client-proof XOR shared-key) 581 The client verifies the server by computing the server-proof 582 directly and comparing. 584 9. Security Considerations 586 Security considerations are discussed throughout this document. 587 The security considerations of MD5 [MD5] and HMAC [HMAC] also 588 apply. SCRAM relies primarily on the one-way characteristic of MD5 589 and HMAC-MD5 for security. The weaknesses found in MD5 are not 590 believed to impact this use. In the interest of avoiding 591 proliferation of authentication mechanisms, it is hoped that it 592 will be easy to deploy public-key technology before a hash function 593 upgrade becomes necessary. 595 SCRAM does use the output of an HMAC function and exclusive-or to 596 construct a simple 16-octet encryption function. While 597 constructing an encryption function from a hash function is 598 normally a questionable practice [SCHNEIER], in this case both the 599 key and the data are outputs of a one-way hash function with a good 600 bit-distribution and the key is used only once (as long as the 601 combined nonces are unique). 603 An analysis of different attacks follows: 605 Passive Network Attacks 607 SCRAM is resistant to replay attacks as long as the appropriate 608 nonce is unique. 610 SCRAM is not resistant to passive dictionary attacks. User 611 education, passphrase setting policy and external confidentiality 612 services can be used to protect against such attacks. 614 SCRAM does not protect against session data eavesdropping. An 615 external confidentiality service is necessary to protect against 616 eavesdropping. TLS [TLS] and IP security ESP [IPESP] are examples 617 of IETF standards-track mechanisms to provide confidentiality. 619 Active Network Attacks 621 If the client fails to verify the server proof, then SCRAM provides 622 no protection from active attacks. 624 SCRAM protects against server impersonation with the server mutual 625 authentication. 627 An attacker could use SCRAM to probe for users by trying each user 628 name twice to see if the salt varies. The server can prevent this 629 attack by inventing consistent salt values for non-users. One way 630 to do this would be to store a random secret and generate the salt 631 using HMAC(user-name, random-secret). 633 SASL is susceptible to downgrade active attacks which reduce the 634 advertised authentication mechanisms to the weakest the server 635 offers. If SCRAM is the weakest mechanism, such attacks can be 636 detected if integrity protection is negotiated on and the client 637 requests a duplicate copy of the server's capability list after 638 authentication (e.g., by re-issuing the CAPABILITY command in 639 IMAP). For a protocol such as ACAP [ACAP], the server SHOULD 640 repeat the greeting line immediately after authentication is 641 completed whenever integrity protection is negotiated on. 643 SCRAM can detect insertion, deletion and modification of session 644 data only if integrity protection is negotiated on. TLS [TLS] or 645 IP security services [IPAUTH, IPESP] may also be used to protect 646 against such tampering. If TLS or IP security integrity protection 647 is active, then the SCRAM integrity layer is unnecessary and SHOULD 648 be negotiated off. 650 Upper level security services, such as SCRAM and TLS, can not 651 protect against denial of service attacks on the TCP/IP layer. In 652 addition, if no integrity layer is used, then SCRAM is vulnerable 653 to TCP session stealing attacks [CERT-IPSPOOF]. IP security 654 services [IPAUTH, IPESP] can protect against many of these attacks. 656 SCRAM is not susceptible to the race and denial of service attacks 657 mentioned in section 9 of the OTP specification [OTP]. 659 Server Attacks 661 A server implementation which does not tolerate input of any length 662 with any content may be susceptible to attacks which permit 663 privileged access to the server. For this reason server 664 implementations MUST be able to accept input of any length with any 665 content although server implementations MAY refuse to authenticate 666 the client if messages exceed the specified maximum lengths. Note 667 that the ANSI C gets() library function does not meet this 668 requirement. 670 An attacker which has access to both the SCRAM verifier and a 671 client exchange for a particular user gains the ability to 672 impersonate that user to other servers using the same salt. An 673 external confidentiality service can make it more difficult to 674 obtain the client exchange, but can not defend against installation 675 of a trojan horse on a compromised server. 677 In the process of authentication, the server gains access to the 678 client-key which is sufficient to impersonate the user to other 679 services with the same salt. 681 The limited service trust feature (step 7 above) includes the 682 service name and the server host name. A server host which is 683 authorized to provide one service can impersonate that service at 684 other hosts in the same realm by an active attack on the DNS system 685 when used by the client. Use of secure DNS [DNSSEC] on the client 686 limits this vulnerability. 688 Client Attacks 690 As SCRAM is designed for user entry of a plain-text passphrase, it 691 is vulnerable to passphrase hijacking by trojan horse clients. OTP 692 [OTP] with an external portable OTP calculator can limit the 693 vulnerability to a single session. 695 10. Intellectual Property Issues and Prior Art 697 The author is not aware of any patents or pending patents which 698 apply to this mechanism. 700 This is primarily a derivative of simple hash-based challenge 701 response systems. The hash-based challenge response idea has 702 existed since at least 1992, when the RIPE project published the 703 SKID algorithm according to [SCHNEIER]. 705 The repeated-hash idea used to verify the client's authenticator is 706 derived from S/KEY [SKEY]. 708 The idea of using salt to protect against global dictionary attacks 709 dates back to at least the Unix /etc/passwd system. There is some 710 discussion of this in [SCHNEIER]. 712 SCRAM combines these techniques. The author of this specification 713 first proposed this idea on a public mailing list on July 16, 1997. 715 11. Multinational Considerations 717 As remote access is a crucial service, users are encouraged to 718 restrict user names and passphrases to the US-ASCII character set. 719 However, if characters outside the US-ASCII character set are used 720 in user names and passphrases, then they are interpreted according 721 to UTF-8 [UTF-8] and it is a protocol error to include any octet 722 sequences not legal for UTF-8. Servers are encouraged to enforce 723 this restriction to discourage clients which use unlabeled 724 character sets in this context. 726 12. References 728 [ABNF] Crocker, Overell, "Augmented BNF for Syntax Specifications: 729 ABNF", RFC 2234, Internet Mail Consortium, Demon Internet Ltd, 730 November 1997. 732 [ACAP] Newman, Myers, "ACAP -- Application Configuration Access 733 Protocol", RFC 2244, Innosoft, Netscape, November 1997. 735 [CERT-IPSPOOF] CERT, "TCP SYN Flooding and IP Spoofing Attacks", 736 CERT CA-96.21, CERT, September 1996. 738 [CRAM-MD5] Klensin, Catoe, Krumviede, "IMAP/POP AUTHorize Extension 739 for Simple Challenge/Response", RFC 2195, MCI, September 1997. 741 [DNSSEC] Eastlake, Kaufman, "Domain Name System Security 742 Extensions", RFC 2065, CyberCash, Iris, January 1997. 744 [HMAC] Krawczyk, Bellare, Canetti, "HMAC: Keyed-Hashing for Message 745 Authentication", RFC 2104, IBM, UCSD, February 1997. 747 [IMAP4] Crispin, M., "Internet Message Access Protocol - Version 748 4rev1", RFC 2060, University of Washington, December 1996. 750 [IPAUTH] Atkinson, "IP Authentication Header", RFC 1826, Naval 751 Research Laboratory, August 1995. 753 [IPESP] Atkinson, "IP Encapsulating Security Payload (ESP)", RFC 754 1827, Naval Research Laboratory, August 1995. 756 [KEYWORDS] Bradner, "Key words for use in RFCs to Indicate 757 Requirement Levels", RFC 2119, Harvard University, March 1997. 759 [MD5] Rivest, "The MD5 Message Digest Algorithm", RFC 1321, MIT 760 Laboratory for Computer Science, April 1992. 762 [OTP] Haller, Metz, "A One-Time Password System", RFC 1938, 763 Bellcore, Kaman Sciences Corporation, May 1996. 765 [OTP-EXT] Metz, "OTP Extended Responses", RFC 2243, The Inner Net, 766 November 1997. 768 [POP3] Myers, J., Rose, M., "Post Office Protocol - Version 3", RFC 769 1939, Carnegie Mellon, Dover Beach Consulting, Inc., May 1996. 771 [RANDOM] Eastlake, Crocker, Schiller, "Randomness Recommendations 772 for Security", RFC 1750, DEC, Cybercash, MIT, December 1994. 774 [SASL] Myers, "Simple Authentication and Security Layer (SASL)", 775 RFC 2222, Netscape Communications, October 1997. 777 [SCHNEIER] Schneier, "Applied Cryptography: Protocols, Algorithms 778 and Source Code in C," John Wiley and Sons, Inc., 1996. 780 [SKEY] Haller, Neil M. "The S/Key One-Time Password System", RFC 781 1760, Bellcore, February 1995. 783 [TLS] Dierks, Allen, "The TLS Protocol Version 1.0", Work in 784 progress. 786 [UTF8] Yergeau, F. "UTF-8, a transformation format of ISO 10646", 787 RFC 2279, Alis Technologies, January 1998. 789 13. Author's Address 791 Chris Newman 792 Innosoft International, Inc. 793 1050 Lakes Drive 794 West Covina, CA 91790 USA 796 Email: chris.newman@innosoft.com 798 A. Appendix - Additional Services 800 Several additional services are needed to make SCRAM useful in more 801 usage scenarios. These include remote authentication database 802 support for servers, authentication database APIs for servers, 803 remote passphrase change support for clients, single-sign-on APIs 804 for clients and management tools. The service-id and server-key 805 are included to facilitate the remote authentication database 806 service. Otherwise these issues are deferred for future work. 808 B. Appendix - HMAC-MD5 Sample Source Code 810 The following sample C source code calls the source code in the MD5 811 specification [MD5] and is derived from the source code in [HMAC]. 812 It is needed by the SCRAM source code in the next section. 814 The client may call hmac_md5_precalc() to save the intermediate 815 HMAC result for later use in hmac_md5_import(). This can be used 816 by a CRAM-MD5 [CRAM-MD5] or a SCRAM-MD5 [SCRAM-MD5] client to save 817 an intermediate result suitable for use with any server without 818 saving the plain-text passphrase. 820 /* hmac-md5.h -- HMAC_MD5 functions 821 */ 822 #define HMAC_MD5_SIZE 16 824 /* intermediate MD5 context */ 825 typedef struct HMAC_MD5_CTX_s { 826 MD5_CTX ictx, octx; 827 } HMAC_MD5_CTX; 829 /* intermediate HMAC state 830 * values stored in network byte order (Big Endian) 831 */ 832 typedef struct HMAC_MD5_STATE_s { 833 UINT4 istate[4]; 834 UINT4 ostate[4]; 835 } HMAC_MD5_STATE; 837 /* One step hmac computation 838 * 839 * digest may be same as text or key 840 */ 841 void hmac_md5(const unsigned char *text, int text_len, 842 const unsigned char *key, int key_len, 843 unsigned char digest[HMAC_MD5_SIZE]); 845 /* create context from key 846 */ 847 void hmac_md5_init(HMAC_MD5_CTX *hmac, 848 const unsigned char *key, int key_len); 850 /* precalculate intermediate state from key 851 */ 852 void hmac_md5_precalc(HMAC_MD5_STATE *hmac, 853 const unsigned char *key, int key_len); 855 /* initialize context from intermediate state 856 */ 857 void hmac_md5_import(HMAC_MD5_CTX *hmac, HMAC_MD5_STATE *state); 859 #define hmac_md5_update(hmac, text, text_len) \ 860 MD5Update(&(hmac)->ictx, (text), (text_len)) 862 /* finish hmac from intermediate result. 863 * Intermediate result is erased. 864 */ 865 void hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE], 866 HMAC_MD5_CTX *hmac); 868 /* hmac-md5.c -- HMAC MD5 Keyed-Hashing by Chris Newman 869 * derived from RFC 2104 by H. Krawczyk, M. Bellare, R.Canetti 870 */ 871 #include 872 #include 873 #include "md5.h" 874 #include "hmac-md5.h" 876 /* for htonl() and ntohl() */ 877 #include 878 #include 880 /* MD5 block size */ 881 #define BLOCK_SIZE 64 883 void hmac_md5_init(HMAC_MD5_CTX *hmac, 884 const unsigned char *key, int key_len) 885 { 886 unsigned char k_pad[BLOCK_SIZE]; /* padded key */ 887 int i; 889 /* if key longer than BLOCK_SIZE bytes reset to MD5(key) */ 890 if (key_len > BLOCK_SIZE) { 891 MD5Init(&hmac->ictx); 892 MD5Update(&hmac->ictx, key, key_len); 893 MD5Final(k_pad, &hmac->ictx); 894 key = k_pad; 895 key_len = HMAC_MD5_SIZE; 896 } 897 /* XOR padded key with inner pad value */ 898 for (i = 0; i < key_len; i++) { 899 k_pad[i] = key[i] ^ 0x36; 900 } 901 while (i < BLOCK_SIZE) { 902 k_pad[i++] = 0x36; 903 } 905 /* Begin inner MD5 */ 906 MD5Init(&hmac->ictx); 907 MD5Update(&hmac->ictx, k_pad, BLOCK_SIZE); 909 /* XOR padded key with outer pad value */ 910 for (i = 0; i < BLOCK_SIZE; ++i) { 911 k_pad[i] ^= (0x36 ^ 0x5c); 912 } 914 /* Begin outer MD5 */ 915 MD5Init(&hmac->octx); 916 MD5Update(&hmac->octx, k_pad, BLOCK_SIZE); 918 /* clean up workspace */ 919 memset(k_pad, 0, BLOCK_SIZE); 920 } 922 void hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE], 923 HMAC_MD5_CTX *hmac) 924 { 925 /* finish inner MD5 */ 926 MD5Final(digest, &hmac->ictx); 927 /* finish outer MD5 */ 928 MD5Update(&hmac->octx, digest, HMAC_MD5_SIZE); 929 MD5Final(digest, &hmac->octx); 930 /* MD5Final zeros context */ 931 } 933 void hmac_md5(const unsigned char *text, int text_len, 934 const unsigned char *key, int key_len, 935 unsigned char digest[HMAC_MD5_SIZE]) 936 { 937 HMAC_MD5_CTX hmac; 939 hmac_md5_init(&hmac, key, key_len); 940 hmac_md5_update(&hmac, text, text_len); 941 hmac_md5_final(digest, &hmac); 942 } 943 void hmac_md5_precalc(HMAC_MD5_STATE *ctx, 944 const unsigned char *pass, int passlen) 945 { 946 HMAC_MD5_CTX hctx; 948 if (passlen == 0) passlen = strlen((const char *) pass); 949 hmac_md5_init(&hctx, pass, passlen); 950 ctx->istate[0] = htonl(hctx.ictx.state[0]); 951 ctx->istate[1] = htonl(hctx.ictx.state[1]); 952 ctx->istate[2] = htonl(hctx.ictx.state[2]); 953 ctx->istate[3] = htonl(hctx.ictx.state[3]); 954 ctx->ostate[0] = htonl(hctx.octx.state[0]); 955 ctx->ostate[1] = htonl(hctx.octx.state[1]); 956 ctx->ostate[2] = htonl(hctx.octx.state[2]); 957 ctx->ostate[3] = htonl(hctx.octx.state[3]); 958 memset(&hctx, 0, sizeof (hctx)); 959 } 961 void hmac_md5_import(HMAC_MD5_CTX *hctx, HMAC_MD5_STATE *ctx) 962 { 963 hctx->ictx.state[0] = ntohl(ctx->istate[0]); 964 hctx->ictx.state[1] = ntohl(ctx->istate[1]); 965 hctx->ictx.state[2] = ntohl(ctx->istate[2]); 966 hctx->ictx.state[3] = ntohl(ctx->istate[3]); 967 hctx->octx.state[0] = ntohl(ctx->ostate[0]); 968 hctx->octx.state[1] = ntohl(ctx->ostate[1]); 969 hctx->octx.state[2] = ntohl(ctx->ostate[2]); 970 hctx->octx.state[3] = ntohl(ctx->ostate[3]); 971 hctx->ictx.count[0] = hctx->octx.count[0] = BLOCK_SIZE << 3; 972 hctx->ictx.count[1] = hctx->octx.count[1] = 0; 973 } 975 C. Appendix - SCRAM sample source code 977 The following sample source code implements SCRAM itself for both 978 server and client. 980 Please note the lines marked "XXX: ..." as they need to be 981 translated from English to computer readable code. 983 A client implementation simply calls scram_md5_generate() with the 984 passphrase after receiving the first server reply. The cproof 985 parameter will hold the message to send to the server and the 986 sproof parameter will hold the expected server mutual 987 authentication. The clidata parameter holds the client's security 988 layer selections. A client may also call hmac_md5_precalc() to 989 turn a passphrase into CRAM/SCRAM credentials for later use in 990 scram_md5_generate(). 992 A server implementation simply calls scram_md5_generate() with the 993 stored verifier, the second client message and the SCRAM_VERIFY 994 option. Server verifiers are generated by creating a random salt 995 and calling scram_md5_vgen() with either the passphrase or 996 CRAM/SCRAM credentials. 998 If integrity protection is desired, the integrity_key parameter may 999 be provided to scram_md5_generate() and will receive the resulting 1000 key. Generating an verifying the integrity protection is left as 1001 an exercise to the reader. 1003 /* scram.h -- scram utility functions 1004 */ 1005 /* size of SCRAM_MD5 salt and verifier */ 1006 #define SCRAM_MD5_SALTSIZE 8 1007 #define SCRAM_MD5_DATASIZE 16 1009 /* SCRAM verifier */ 1010 typedef struct SCRAM_MD5_VRFY_s { 1011 unsigned char salt[SCRAM_MD5_SALTSIZE]; 1012 unsigned char clidata[SCRAM_MD5_DATASIZE]; 1013 unsigned char svrdata[SCRAM_MD5_DATASIZE]; 1014 } SCRAM_MD5_VRFY; 1016 /* Client proof message */ 1017 typedef struct SCRAM_MD5_CLIENT_s { 1018 unsigned char secprops[4]; 1019 unsigned char cproof[SCRAM_MD5_DATASIZE]; 1020 } SCRAM_MD5_CLIENT; 1022 /* generate SCRAM-MD5 verifier 1023 * vptr -- gets result 1024 * salt -- contains salt of SCRAM_MD5_SALTSIZE 1025 * pass -- passphrase or verifier 1026 * passlen -- len of pass/verifier (0 ok if NUL terminated) 1027 * plainflag -- 1 = plaintext passphrase, 1028 * 0 = result of hmac_md5_precalc() 1029 * clientkey -- cache for client proof, usually NULL 1030 */ 1031 void scram_md5_vgen(SCRAM_MD5_VRFY *vptr, 1032 const unsigned char *salt, 1033 const char *pass, int passlen, int plainflag, 1034 unsigned char *clientkey); 1036 /* scram secret action type */ 1037 #define SCRAM_CREDENTIAL 0 /* generate replies using credentials */ 1038 #define SCRAM_PLAINTEXT 1 /* generate replies using plaintext */ 1039 #define SCRAM_VERIFY 2 /* use SCRAM_MD5_VRFY to verify client, 1040 and generate server reply */ 1042 /* generate or verify SCRAM-MD5 1043 * input params: 1044 * cchal -- client challenge string 1045 * cchallen -- length of client challenge 1046 * schal -- server challenge string 1047 * schallen -- length of server challenge 1048 * secret -- passphrase, credentials, or verifier 1049 * secretlen -- length of passphrase (0 ok if NUL terminated) 1050 * action -- see above 1051 * in/out: 1052 * clidata -- client data for client response 1053 * output: 1054 * sproof -- server proof of length SCRAM_MD5_DATASIZE 1055 * integrity_key -- integrity key of length SCRAM_MD5_DATASIZE 1056 * caller may pass NULL if no integrity needed 1057 * returns: 1058 * -2 if params invalid 1059 * -1 if verify fails 1060 * 0 on success 1061 */ 1062 int scram_md5_generate(const char *cchal, int cchallen, 1063 const char *schal, int schallen, 1064 const char *secret, int secretlen, 1065 int action, 1066 SCRAM_MD5_CLIENT *clidata, 1067 unsigned char *sproof, 1068 unsigned char *integrity_key); 1070 /* scram.c -- routines for SCRAM-MD5 calculations 1071 */ 1072 #include 1073 #include 1074 #include 1075 #include "md5.h" 1076 #include "hmac-md5.h" 1077 #include "scram.h" 1079 void scram_md5_vgen(SCRAM_MD5_VRFY *vptr, 1080 const unsigned char *salt, 1081 const char *pass, int passlen, int plainflag, 1082 unsigned char *clientkey) 1083 { 1084 HMAC_MD5_CTX hctx; 1086 if (clientkey == NULL) clientkey = vptr->clidata; 1088 /* get context */ 1089 if (plainflag) { 1090 if (passlen == 0) passlen = strlen(pass); 1091 hmac_md5_init(&hctx, (const unsigned char *) pass, 1092 passlen); 1093 } else { 1094 hmac_md5_import(&hctx, (HMAC_MD5_STATE *) pass); 1095 } 1097 /* generate salted passphrase */ 1098 hmac_md5_update(&hctx, salt, SCRAM_MD5_SALTSIZE); 1099 hmac_md5_final(vptr->clidata, &hctx); 1101 /* generate server proof */ 1102 hmac_md5(salt, SCRAM_MD5_SALTSIZE, vptr->clidata, 1103 sizeof (vptr->clidata), vptr->svrdata); 1105 /* generate client key and client verifier */ 1106 MD5Init(&hctx.ictx); 1107 MD5Update(&hctx.ictx, vptr->clidata, sizeof (vptr->clidata)); 1108 MD5Final(clientkey, &hctx.ictx); 1109 MD5Init(&hctx.ictx); 1110 MD5Update(&hctx.ictx, clientkey, SCRAM_MD5_DATASIZE); 1111 MD5Final(vptr->clidata, &hctx.ictx); 1113 /* copy salt to verifier */ 1114 if (salt != vptr->salt) { 1115 memcpy(vptr->salt, salt, SCRAM_MD5_SALTSIZE); 1116 } 1117 } 1118 int scram_md5_generate(const char *cchal, int cchallen, 1119 const char *schal, int schallen, 1120 const char *secret, int secretlen, 1121 int action, 1122 SCRAM_MD5_CLIENT *clidata, 1123 unsigned char *sproof, 1124 unsigned char *integrity_key) 1125 { 1126 SCRAM_MD5_VRFY verifier, *vptr; 1127 HMAC_MD5_CTX hctx; 1128 unsigned char clientkey[HMAC_MD5_SIZE]; 1129 unsigned char sharedkey[HMAC_MD5_SIZE]; 1130 int i, result = 0; 1132 /* check params */ 1133 if ((action == SCRAM_CREDENTIAL 1134 && secretlen != sizeof (HMAC_MD5_STATE)) 1135 || (action == SCRAM_VERIFY 1136 && secretlen != sizeof (verifier)) 1137 || schallen < SCRAM_MD5_SALTSIZE) { 1138 return (-2); 1139 } 1141 /* get verifier */ 1142 if (action == SCRAM_VERIFY) { 1143 vptr = (SCRAM_MD5_VRFY *) secret; 1144 } else { 1145 scram_md5_vgen(&verifier, (const unsigned char *) schal, 1146 secret, secretlen, action, clientkey); 1147 vptr = &verifier; 1148 } 1150 /* calculate shared key */ 1151 hmac_md5_init(&hctx, vptr->clidata, sizeof (vptr->clidata)); 1152 hmac_md5_update(&hctx, (unsigned char *) schal, schallen); 1153 hmac_md5_update(&hctx, (unsigned char *) cchal, cchallen); 1154 hmac_md5_update(&hctx, clidata->secprops, 4); 1155 hmac_md5_final(sharedkey, &hctx); 1157 if (action == SCRAM_VERIFY) { 1158 /* verify client proof */ 1159 for (i = 0; i < HMAC_MD5_SIZE; ++i) { 1160 XXX: the line which belongs here is omitted due to 1161 U.S. export regulations, but it exclusive-ors the 1162 "sharedkey" with the "clidata->cproof" and places the 1163 result in "clientkey" (see step (c) above) 1164 } 1165 MD5Init(&hctx.ictx); 1166 MD5Update(&hctx.ictx, clientkey, sizeof (clientkey)); 1167 MD5Final(sharedkey, &hctx.ictx); 1168 if (memcmp(sharedkey, vptr->clidata, 1169 sizeof (sharedkey)) != 0) { 1170 result = -1; 1171 } 1172 } else { 1173 /* generate client proof */ 1174 for (i = 0; i < HMAC_MD5_SIZE; ++i) { 1175 XXX: the line which belongs here is omitted due to 1176 U.S. export regulations, but it exclusive-ors the 1177 "sharedkey" with the "clientkey" and places the 1178 result in "clidata->cproof" (see step (G) above) 1179 } 1180 } 1182 /* calculate integrity key */ 1183 if (integrity_key != NULL) { 1184 hmac_md5_init(&hctx, clientkey, HMAC_MD5_SIZE); 1185 hmac_md5_update(&hctx, (unsigned char *) schal, schallen); 1186 hmac_md5_update(&hctx, (unsigned char *) cchal, cchallen); 1187 hmac_md5_update(&hctx, clidata->secprops, 4); 1188 hmac_md5_final(integrity_key, &hctx); 1189 } 1191 /* calculate server result */ 1192 if (result == 0) { 1193 hmac_md5_init(&hctx, vptr->svrdata, HMAC_MD5_SIZE); 1194 hmac_md5_update(&hctx, (unsigned char *) cchal, cchallen); 1195 hmac_md5_update(&hctx, (unsigned char *) schal, schallen); 1196 hmac_md5_update(&hctx, clidata->secprops, 4); 1197 hmac_md5_final(sproof, &hctx); 1198 } 1200 /* cleanup workspace */ 1201 memset(clientkey, 0, sizeof (clientkey)); 1202 memset(sharedkey, 0, sizeof (sharedkey)); 1203 if (vptr == &verifier) memset(&verifier, 0, sizeof (verifier)); 1205 return (result); 1206 }