idnits 2.17.1 draft-newman-auth-scram-02.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-03-29) 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 529 has weird spacing: '...secinfo clien...' == Line 530 has weird spacing: '...secinfo serve...' == Line 531 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 (January 1998) is 9570 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 693, but not defined -- Looks like a reference, but probably isn't: '01000000' on line 397 -- Looks like a reference, but probably isn't: '00' on line 397 == Missing Reference: 'SCRAM-MD5' is mentioned on line 809, but not defined -- Looks like a reference, but probably isn't: '4' on line 1015 -- Looks like a reference, but probably isn't: '0' on line 968 -- Looks like a reference, but probably isn't: '1' on line 969 -- Looks like a reference, but probably isn't: '2' on line 966 -- Looks like a reference, but probably isn't: '3' on line 967 == Unused Reference: 'OTP-EXT' is defined on line 746, but no explicit reference was found in the text == Unused Reference: 'UTF8' is defined on line 777, but no explicit reference was found in the text ** Obsolete normative reference: RFC 2234 (ref. 'ABNF') (Obsoleted by RFC 4234) ** 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) ** 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 2044 (ref. 'UTF8') (Obsoleted by RFC 2279) Summary: 19 errors (**), 0 flaws (~~), 9 warnings (==), 12 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-02.txt January 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 protection from active attacks without 34 a significant increase in complexity. SCRAM is intended for use 35 with services which need a simple, fast and flexible authentication 36 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 underlying connection (with the exception of dictionary 69 attacks) as primary design goals. It has managability, backwards 70 compatibility with CRAM-MD5 intermediate HMAC state verifiers, some 71 protection 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 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: the client key which 108 is derived from the passphrase and salt, the client verifier which 109 is simply the one-way hash function applied to the client key, and 110 the server key which is also derived from the passphrase and salt. 111 The server has access to the salt, client verifier and server key 112 for each user. 114 SCRAM uses HMAC to sign client and server nonces with the client 115 verifier to produce a shared key. The client exclusive-ors the 116 shared key with the client key and sends that to the server which 117 can reverse the exclusive-or operation and verify that the hash 118 function applied to the client key is equal to the client verifier. 119 The server uses HMAC to sign the client and server nonces with the 120 server key and sends that to the client to authenticate. 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 2.3. Intended Use 129 SCRAM is designed for a usage scenario where simplicity and/or 130 speed is important, frequent authentications may occur and the 131 primary threat is passive and active network attacks. A good 132 example of protocols whose usage and threat model fit SCRAM are 133 IMAP [IMAP4] and POP3 [POP3]. SCRAM provides limited protection 134 against threats to the server authentication database, but OTP 135 [OTP] may be preferable for usage scenarios where the threat to the 136 server is more serious and active attacks are not an issue. 138 3. Client Implementation of SCRAM-MD5 140 This section includes a step-by-step guide for client implementors. 141 Section 6 contains the formal definition of the syntax and is the 142 authoritative reference in case of errors here. 144 When used with SASL the mechanism name is "SCRAM-MD5". The 145 mechanism does not provide a privacy layer, but does include an 146 optional integrity protection layer. 148 The client begins by sending a message to the server containing the 149 following three pieces of information. 151 (1) An authorization identity. When the empty string is used, this 152 defaults to the authentication identity. This is used by system 153 administrators or proxy servers to login with a different user 154 identity. This field may be up to 255 octets and is terminated by 155 a NUL (0) octet. US-ASCII printable characters are preferred, 156 although UTF-8 [UTF-8] printable characters are permitted to 157 support international names. Use of character sets other than 158 US-ASCII and UTF-8 is forbidden. 160 (2) An authentication identity. The identity whose passphrase will 161 be used. This field may be up to 255 octets and is terminated by a 162 NUL (0) octet. US-ASCII printable characters are preferred, 163 although UTF-8 [UTF-8] printable characters are permitted to 164 support international names. Use of character sets other than 165 US-ASCII and UTF-8 is forbidden. 167 (3) A "client nonce." It is important that this be globally 168 unique. One common technique for generating globally unique 169 identifiers combines a process identifier with the system clock, a 170 sequence number, a random number and the client's domain name. The 171 random number is important as clocks are often synchronized using 172 insecure protocols and are predictable. Advice for generating good 173 random numbers can be found in [RANDOM]. 175 The server responds by sending a message containing three pieces of 176 information: 178 (4) An 8-octet salt value, specific to the authentication identity. 180 (5) A one-octet bit-mask specifying security layers supported by 181 the server. Bit 0 (value 1) indicates support for no security 182 layer and bit 1 (value 2) indicates support for an integrity 183 protection layer. The other bits are reserved for future use (the 184 server MUST set them to zero until they are defined in a standards 185 track specification). If the client doesn't support a security 186 layer and bit 0 is cleared, then the authentication immediately 187 fails. 189 (6) A three-octet number in network byte order (big endian), 190 containing the maximum cipher-text buffer size the server is able 191 to receive. This may be 0 if the server supports no security 192 layers. 194 (7) A service id consisting of the service name of the protocol's 195 SASL profile followed by an "@" followed by the domain name of the 196 server and terminated by NUL. The client SHOULD verify this is 197 correct. 199 (8) A "server nonce". As the domain name is included in (7), this 200 only has to be unique to the server. 202 The client then does the following: 204 (A) Create a buffer containing the user's passphrase. The client 205 MUST support passphrases of at least 64 octets. US-ASCII 206 characters are preferred, although UTF-8 characters are permitted. 207 Character sets other than US-ASCII and UTF-8 MUST NOT be used. 209 (B) Apply the HMAC-MD5 function with (A) as the key and the 8-octet 210 salt as the data, producing a 16-octet result. Once this is done, 211 (A) SHOULD be erased from memory. 213 (C) Apply the MD5 function to the result of (B). This produces a 214 16-octet result. 216 (D) Apply the MD5 function to the result of (C). This produces a 217 16-octet result. 219 (E) Create a buffer containing the server's response (4)-(8), 220 immediately followed by the initial client message (1)-(3) and the 221 client's security layer selection (9)-(10) below. 223 (F) Apply the HMAC-MD5 function with the result of (D) as the key 224 and the buffer from (E) as the data. This produces a 16-octet 225 result. 227 (G) Create a 16-octet buffer containing the exclusive-or of (C) and 228 (F). 230 The client then sends a message to the server containing the 231 following: 233 (9) A bit-mask indicating the client selected security layer from 234 step (5). This has a value of 01 for no security layer and 02 for 235 an integrity protection layer. 237 (10) A three octet number indicating the maximum cipher-text buffer 238 size the client is able to receive in network byte order. If the 239 client doesn't select a security layer, this may be all zeros. 241 (11) The 16-octet result of step (G). 243 The server will respond with: 245 (12) A 16-octet server authentication verifier. 247 The client SHOULD verify this with the following procedure: 249 (H) Apply the HMAC-MD5 function with the result of (B) as the key 250 and the 8-octet salt as the data. This produces a 16-octet result. 252 (I) Create a buffer containing the initial client message (1)-(3) 253 immediately followed by the initial server response (4)-(8) and the 254 client's security layer selection (9)-(10). 256 (J) Apply the HMAC-MD5 function with the result of (H) as the key 257 and the buffer from (I) as the data. 259 (K) If the result of (J) matches (12), the server is authenticated. 261 A secured client MAY store the result of (B) to re-authenticate to 262 services using the same salt, or the intermediate HMAC state from 263 (B) to re-authenticate to any service. Clients SHOULD NOT store 264 the passphrase itself. 266 If integrity protection is negotiated on, the following procedure 267 is applied to each SASL security layer packet sent by the client: 269 (L) Apply the HMAC-MD5 function with the output of step (C) as the 270 key and the buffer from step (E) as the value. 272 (M) A buffer is created containing a four octet client packet 273 number in network byte order followed by the 16-octet output of 274 step (L). The first packet sent under the SASL security layer is 275 given number 1. 277 (N) Apply the HMAC-MD5 function with (M) as the key and the 278 contents of the packet as the data. The result is appended to the 279 end of the packet. 281 The integrity protection on packets from the server is verified as 282 follows: 284 (O) A buffer is created containing a four octet server packet 285 number in network byte order followed by the 16-octet output of 286 step (L) above. This first packet sent under the SASL security 287 layer is given number 1. 289 (P) Apply the HMAC-MD5 function with (O) as the key and all but the 290 last 16 octets of the packet as the value. 292 (Q) Compare the last 16 octets of the packet to the output of (P). 293 If they do not match, an integrity error is produced. 295 4. Server Implementation of SCRAM-MD5 297 The section includes a step-by-step guide for server implementors 298 building on the previous section. Section 6 contains the formal 299 definition of the syntax and is the authoritative reference in case 300 of errors here. 302 The server's authentication database contains an 8-octet salt, 303 16-octet client verifier and a 16-octet server key for each local 304 user. The server MUST support "user@host" syntax for the 305 authentication identity at least to the extent of stripping "@host" 306 when it matches the local hostname or rejecting the authentication 307 if the hostname doesn't match. The server MAY support remote user 308 authentication using this syntax. 310 The stored client verifier is equal to the result of step (D) 311 above, and the stored server key is equal to the result of step (J) 312 above. To create its initial response, the server simply looks up 313 the authentication identity to fetch the salt, and generates an 8 314 to 248 octet nonce. This nonce MUST be unique for the server to 315 prevent replay attacks. It can be generated by appending a system 316 clock to a process and/or thread identifier and a random number 317 [RANDOM]. To verify the client's credentials, the server performs 318 the following steps: 320 (a) Generate a buffer identical to step (E) above. 322 (b) Apply the HMAC-MD5 function with the stored client verifier as 323 the key and the result of (a) as the data. This produces a 324 16-octet result equal to step (F) above. 326 (c) Exclusive-or the result of (b) with message (11) from the 327 client. This produces a 16-octet result which should be equal to 328 the result of step (C) above. 330 (d) Apply the MD5 function to the output of step (c). This 331 produces a 16-octet result which should be equal to the result of 332 step (D) above. 334 (e) if the result of (d) is equal to the stored verifier, then the 335 user is authenticated. 337 If no client challenge was provided in step (3), the server is now 338 done and responds with the appropriate status code. Otherwise the 339 server continues as follows: 341 (f) Generate a buffer identical to step (I) above. 343 (g) Apply the HMAC-MD5 function with the stored server verifier as 344 the key and the buffer from (f) as the data. This produces a 345 16-octet result. 347 The result of (g) is sent to the client to authenticate the server. 349 If integrity protection is negotiated on, the integrity key is 350 computed as follows: 352 (h) Apply the HMAC-MD5 function with the output of step (c) as the 353 key and the buffer from step (a) as the data. 355 Integrity generation and verification works in the same fashion as 356 the client. 358 5. Example 360 In these examples, "C:" represents lines sent from the client to 361 the server and "S:" represents lines sent from the server to the 362 client. The wrapped lines are for editorial clarity -- there are 363 no actual newlines in the middle of the messages. 365 The following is an example of the SCRAM-MD5 mechanism using the 366 IMAP [IMAP4] profile of SASL. For this example, the user "chris", 367 with an empty authorization identity is using the passphrase 368 "secret stuff". The client nonce is 369 "" and the server 370 nonce is "jhcNZlRuPbziFp+vLV+NCw". No security layer is supported, 371 the salt is "testsalt" and the service identity is 372 "imap@eleanor.innosoft.com". The complete 40 octet verifier stored 373 on the server, in hexidecimal is "74657374 73616c74 16484d56 374 7ee02f47 ac5f8a5a d5795570 90d55334 d2002df6 24cb8c8b 75708f4e." 375 C: a001 AUTHENTICATE SCRAM-MD5 376 S: + 377 C: AGNocmlzADx0NG40UGFiOUhCMEFtL1FMWEI3MmVnQGVsZWFub3IuaW 378 5ub3NvZnQuY29tPg== 379 S: + dGVzdHNhbHQBAAAAaW1hcEBlbGVhbm9yLmlubm9zb2Z0LmNvbQBq 380 aGNOWmxSdVBiemlGcCt2TFYrTkN3 381 C: AQAAAMg9jU8CeB4KOfk7sUhSQPs= 382 S: + U0odqYw3B7XIIW0oSz65OQ== 383 C: 384 S: a001 OK AUTHENTICATE completed 386 Note that base64 encoding and the lack of an initial client 387 response with the first command are characteristics of the IMAP 388 profile of SASL and not characteristics of SASL or SCRAM-MD5. Here 389 is another example using the ACAP [ACAP] profile of SASL. This 390 uses the same salt, passphrase and verifier as the previous 391 example. In this example, binary data is represented as 392 hexidecimal digits enclosed in square brackets: 394 C: a001 AUTHENTICATE "SCRAM-MD5" {52} 395 C: [00]chris[00] 396 S: + {60} 397 S: testsalt[01000000]acap@eleanor.innosoft.com[00] 398 m6HdEYWZA5W8keNbiY40aA 399 C: {20} 400 C: [01000000 19b66406 4ce8138a e0af7b0b f0ed20ea] 401 S: a001 OK (SASL {16} 402 S: [44d7c1c4 0630fea6 5c49cb40 717a2ba5]) "Successful" 404 Note that arbitrary binary values may be used for the salt and 405 nonces, as long as the client nonce is globally unique. 407 6. Formal Syntax of SCRAM-MD5 Messages 409 This is the formal syntactic definition of the client and server 410 messages. This uses ABNF [ABNF] notation including the core rules. 412 client-msg-1 = [authorize-id] NUL authenticate-id NUL nonce 414 server-msg-1 = salt security-info service-id NUL nonce 416 client-msg-2 = security-info client-proof 418 server-msg-2 = server-proof 420 passphrase = *UTF8-SAFE 421 ;; At least 64 octets MUST be supported 423 authorize-id = *UTF8-PRINT 424 ;; No more than 255 octets 426 authenticate-id = *UTF8-PRINT 427 ;; No more than 255 octets 429 security-info = secbits bufsize 431 bufsize = 3OCTET 432 ;; in network byte order (big-endian) 434 secbits = OCTET 435 ;; bit 0 = no protection, bit 1 = integrity, 436 ;; other bits set to 0 and reserved 438 service-id = service-name "@" server-domain 440 service-name = *VCHAR 441 ;; a SASL/GSSAPI service name 443 server-domain = *VCHAR 444 ;; an internet domain name 446 nonce = 8*OCTET 448 salt = 8OCTET 450 client-proof = 16OCTET 452 server-proof = 16OCTET 454 NUL = %x00 ;; US-ASCII NUL character 456 UTF8-SAFE = %x01-09 / %x0B-0C / %x0E-7F / UTF8-MULTI 457 ;; Any character except CR, LF, NUL 459 UTF8-PRINT = %x20-7E / UTF8-MULTI 460 ;; Any character except CTLs 462 UTF8-MULTI = UTF8-2 / UTF8-3 / UTF8-4 / UTF8-5 / UTF8-6 463 ;; UTF-8 Multi-octet characters 465 UTF8-1 = %x80-BF 467 UTF8-2 = %xC0-DF UTF8-1 469 UTF8-3 = %xE0-EF 2UTF8-1 470 UTF8-4 = %xF0-F7 3UTF8-1 472 UTF8-5 = %xF8-FB 4UTF8-1 474 UTF8-6 = %xFC-FD 5UTF8-1 476 7. System Administrator Advice 478 This section includes advice for system administrators using this 479 mechanism. 481 A SCRAM server stores three pieces of information for each user: a 482 salt, a client verifier and server key. The latter two are derived 483 from the salt and the user's passphrase. 485 The salt prevents global dictionary attacks, similar to the salt 486 used in Unix /etc/passwd files. As the 12 bits of salt in Unix 487 /etc/passwd has proved to be insufficient, SCRAM uses 64 bits of 488 salt. See [SCHNEIER] for a good discussion of salt and dictionary 489 attacks. In a multi-server site, security can be increased by 490 using a different salt on each server. 492 Although the verifiers used by SCRAM-MD5 have roughly comparable 493 security to those used by current plain-text mechanisms (such as 494 Unix /etc/passwd), it is still very important to keep them secret. 495 Just as tools exist to try common passwords against Unix 496 /etc/passwd files, it is also possible to build such tools for 497 SCRAM-MD5. In addition, once a SCRAM-MD5 verifier is stolen, a 498 passive (undetectable) eavesdropper of that user logging in gains 499 the output of step (C) above, which is sufficient to impersonate 500 the user to all services with the same salt. This is better than 501 current plain-text mechanisms where a passive eavesdropper always 502 recovers the user's password, but is still a serious concern. 504 Verifiers SHOULD be kept hidden from all users on the server. 505 Sites which distribute verifiers among multiple servers, SHOULD 506 encrypt them when transferring them over the network. 508 SCRAM-MD5 is only a good mechanism if passphrases are well chosen. 509 For this reason, implementations should use the term "passphrase" 510 rather than "password" and when a user's passphrase is set, site 511 policy restrictions should be applied. A reasonably secure site 512 policy would require passphrases of at least 10 characters with at 513 least one non-alphanumeric character. 515 SCRAM-MD5 doesn't protect the privacy of data exchanged after 516 authentication. Use of TLS [TLS] or a stronger SASL mechanism such 517 as Kerberos is encouraged if this functionality is needed. 519 8. SCRAM Functional Notation 521 This section is designed to provide a quick understanding of SCRAM 522 for those who like functional notation. 524 + octet concatenation 525 XOR the exclusive-or function 526 AU is the authentication user identity (NUL terminated) 527 AZ is the authorization user identity (NUL terminated) 528 if AZ is the same as AU, a single NUL is used instead. 529 csecinfo client security layer option bits and buffer size 530 ssecinfo server security layer option bits and buffer size 531 service is the name of the service and server (NUL terminated) 532 pass is the plain-text passphrase 533 H(x) is a one-way hash function applied to "x", such as MD5 534 MAC(x,y) is a message authentication code (MAC) such as HMAC-MD5 535 "y" is the key and "x" is the text signed by the key. 536 salt is a per-user salt value the server stores 537 Us is a unique nonce the server sends to the client 538 Uc is a unique nonce the client sends to the server 540 The SCRAM computations and exchange are as follows: 542 client-msg-1 = AZ + AU + Uc 543 (1) client -> server: client-msg-1 544 server-msg-1 = salt + ssecinfo + service + Us 545 (2) server -> client: server-msg-1 546 salted-pass = MAC(salt, pass) 547 client-key = H(salted-pass) 548 client-verifier = H(client-key) 549 shared-key = MAC(server-msg-1 + client-msg-1 + csecinfo, 550 client-verifier) 551 client-proof = client-key XOR shared-key 552 (3) client -> server: client-proof + secinfo 553 server-key = MAC(salt, salted-pass) 554 server-proof = MAC(client-msg-1 + server-msg-1 + csecinfo, 555 server-key) 556 (4) server -> client: server-proof 557 integrity-key = MAC(server-msg-1 + client-msg-1 + csecinfo, 558 client-key) 560 The server stores the salt, client-verifier and server-key. It 561 authenticates the client by computing: 563 H(client-proof XOR shared-key) 565 after step 3 and comparing it to the stored client-verifier. The 566 server computes the integrity-key with: 568 MAC(server-msg-1 + client-msg-1, client-proof XOR shared-key) 570 The client verifies the server by computing the server-proof 571 directly and comparing. 573 9. Security Considerations 575 Security considerations are discussed throughout this document. 576 The security considerations of MD5 [MD5] and HMAC [HMAC] also 577 apply. SCRAM relies primarily on the one-way characteristic of MD5 578 and HMAC-MD5 for security. The weaknesses found in MD5 are not 579 believed to impact this use. In the interest of avoiding 580 proliferation of authentication mechanisms, it is hoped that it 581 will be easy to deploy public-key technology before a hash function 582 upgrade becomes necessary. 584 SCRAM does use the output of an HMAC function and exclusive-or to 585 construct a simple 16-octet encryption function. While 586 constructing an encryption function from a hash function is 587 normally a questionable practice [SCHNEIER], in this case both the 588 key and the data are outputs of a one-way hash function with a good 589 bit-distribution and the key is used only once (as long as the 590 combined nonces are unique). 592 An analysis of different attacks follows: 594 Passive Network Attacks 596 SCRAM is resistant to replay attacks as long as the appropriate 597 nonce is unique. 599 SCRAM is not resistant to passive dictionary attacks. User 600 education, passphrase setting policy and TLS [TLS] can be used to 601 protect against such attacks. 603 SCRAM does not protect against session data eavesdropping. TLS 604 [TLS] can be used to protect against this. 606 Active Network Attacks 608 If the client fails to verify the server proof, then SCRAM provides 609 no protection from active attacks. 611 SCRAM protects against server impersonation with the server mutual 612 authentication. 614 An attacker could use SCRAM to probe for users by trying each user 615 name twice to see if the salt varies. The server can prevent this 616 attack by inventing consistent salt values for non-users. One way 617 to do this would be to store a random secret and generate the salt 618 using HMAC(user-name, random-secret). 620 SASL is susceptible to downgrade active attacks which reduce the 621 advertised authentication mechanisms to the weakest the server 622 offers. If SCRAM is the weakest mechanism, such attacks can be 623 detected if integrity protection is negotiated on and the client 624 requests a duplicate copy of the server's capability list after 625 authentication (e.g., by re-issuing the CAPABILITY command in 626 IMAP). For a protocol such as ACAP [ACAP], the server SHOULD 627 repeat the greeting line immediately after authentication is 628 completed whenever integrity protection is negotiated on. 630 SCRAM can protect against connection tampering only if integrity 631 protection is negotiated on. TLS [TLS] or IPAUTH [IPAUTH] may also 632 be used to protect against such tampering. If TLS or IPAUTH is 633 active, then the SCRAM integrity layer is unnecessary and SHOULD be 634 negotiated off. 636 SCRAM does not protect against most active denial of service 637 attacks, although it is less susceptible to such attacks than OTP 638 [OTP]. 640 Server Attacks 642 A server implementation which does not tolerate input of any length 643 with any content may be susceptible to attacks which permit 644 privileged access to the server. For this reason server 645 implementations MUST be able to accept input of any length with any 646 content although server implementations MAY refuse to authenticate 647 the client if messages exceed the specified maximum lengths. 649 An attacker which has access to both the SCRAM verifier and a 650 client exchange for a particular user gains the ability to 651 impersonate that user to other servers using the same salt. TLS 652 [TLS] can make it more difficult to obtain the client exchange, but 653 can not defend against installation of a trojan horse on a 654 compromised server. 656 In the process of authentication, the server gains access to the 657 client-key which is sufficient to impersonate the user to other 658 services with the same salt. 660 Client Attacks 662 As SCRAM is designed for user entry of a plain-text passphrase, it 663 is vulnerable to passphrase hijacking by trojan horse clients. OTP 664 [OTP] with an external portable OTP calculator can limit the 665 vulnerability to a single session. 667 10. Intellectual Property Issues and Prior Art 669 The author is not aware of any patents or pending patents which 670 apply to this mechanism. 672 This is primarily a derivative of simple hash-based challenge 673 response systems. The hash-based challenge response idea has 674 existed since at least 1992, when the RIPE project published the 675 SKID algorithm according to [SCHNEIER]. 677 The repeated-hash idea used to verify the client's authenticator is 678 derived from S/KEY [SKEY]. 680 The idea of using salt to protect against global dictionary attacks 681 dates back to at least the Unix /etc/passwd system. There is some 682 discussion of this in [SCHNEIER]. 684 SCRAM combines these techniques. The author of this specification 685 first proposed this idea on a public mailing list on July 16, 1997. 687 11. Multinational Considerations 689 As remote access is a crucial service, users are encouraged to 690 restrict user names and passphrases to the US-ASCII character set. 691 However, if characters outside the US-ASCII chracter set are used 692 in user names and passphrases, then they are interpreted according 693 to UTF-8 [UTF-8] and it is a protocol error to include any octet 694 sequences not legal for UTF-8. Servers are encourged to enforce 695 this restriction to discourage clients which use unlabelled 696 character sets in this context. 698 12. References 700 [ABNF] Crocker, Overell, "Augmented BNF for Syntax Specifications: 701 ABNF", RFC 2234, Internet Mail Consortium, Demon Internet Ltd, 702 November 1997. 704 706 [ACAP] Newman, Myers, "ACAP -- Application Configuration Access 707 Protocol", RFC 2244, Innosoft, Netscape, November 1997. 709 711 [CRAM-MD5] Klensin, Catoe, Krumviede, "IMAP/POP AUTHorize Extension 712 for Simple Challenge/Response", RFC 2195, MCI, September 1997. 714 716 [HMAC] Krawczyk, Bellare, Canetti, "HMAC: Keyed-Hashing for Message 717 Authentication", RFC 2104, IBM, UCSD, February 1997. 719 721 [IMAP4] Crispin, M., "Internet Message Access Protocol - Version 722 4rev1", RFC 2060, University of Washington, December 1996. 724 726 [IPAUTH] Atkinson, "IP Authentication Header", RFC 1826, Naval 727 Research Laboratory, August 1995. 729 731 [KEYWORDS] Bradner, "Key words for use in RFCs to Indicate 732 Requirement Levels", RFC 2119, Harvard University, March 1997. 734 736 [MD5] Rivest, "The MD5 Message Digest Algorithm", RFC 1321, MIT 737 Laboratory for Computer Science, April 1992. 739 741 [OTP] Haller, Metz, "A One-Time Password System", RFC 1938, 742 Bellcore, Kaman Sciences Corporation, May 1996. 744 746 [OTP-EXT] Metz, "OTP Extended Responses", RFC 2243, The Inner Net, 747 November 1997. 749 751 [POP3] Myers, J., Rose, M., "Post Office Protocol - Version 3", RFC 752 1939, Carnegie Mellon, Dover Beach Consulting, Inc., May 1996. 754 756 [RANDOM] Eastlake, Crocker, Schiller, "Randomness Recommendations 757 for Security", RFC 1750, DEC, Cybercash, MIT, December 1994. 759 761 [SASL] Myers, "Simple Authentication and Security Layer (SASL)", 762 RFC 2222, Netscape Communications, October 1997. 764 766 [SCHNEIER] Schneier, "Applied Cryptography: Protocols, Algorithms 767 and Source Code in C," John Wiley and Sons, Inc., 1996. 769 [SKEY] Haller, Neil M. "The S/Key One-Time Password System", RFC 770 1760, Bellcore, February 1995. 772 774 [TLS] Dierks, Allen, "The TLS Protocol Version 1.0", Work in 775 progress. 777 [UTF8] Yergeau, F. "UTF-8, a transformation format of Unicode and 778 ISO 10646", RFC 2044, Alis Technologies, October 1996. 780 782 13. Author's Address 784 Chris Newman 785 Innosoft International, Inc. 786 1050 Lakes Drive 787 West Covina, CA 91790 USA 789 Email: chris.newman@innosoft.com 791 A. Appendix - Additional Services 793 Several additional services are needed to make SCRAM useful in more 794 usage scenarios. These include remote authentication database 795 support for servers, authentication database APIs for servers, 796 remote passphrase change support for clients, single-sign-on APIs 797 for clients and management tools. The service-id and server-key 798 are included to facilitate the remote authentication database 799 service. Otherwise these issues are deferred for future work. 801 B. Appendix - HMAC-MD5 Sample Source Code 803 The following sample C source code calls the source code in the MD5 804 specification [MD5] and is derived from the source code in [HMAC]. 805 It is needed by the SCRAM source code in the next section. 807 The client may call hmac_md5_precalc() to save the intermediate 808 HMAC result for later use in hmac_md5_import(). This can be used 809 by a CRAM-MD5 [CRAM-MD5] or a SCRAM-MD5 [SCRAM-MD5] client to save 810 an intermediate result suitable for use with any server without 811 saving the plain-text passphrase. 813 /* hmac-md5.h -- HMAC_MD5 functions 814 */ 815 #define HMAC_MD5_SIZE 16 817 /* intermediate MD5 context */ 818 typedef struct HMAC_MD5_CTX_s { 819 MD5_CTX ictx, octx; 820 } HMAC_MD5_CTX; 822 /* intermediate HMAC state 823 * values stored in network byte order (Big Endian) 824 */ 825 typedef struct HMAC_MD5_STATE_s { 826 UINT4 istate[4]; 827 UINT4 ostate[4]; 828 } HMAC_MD5_STATE; 830 /* One step hmac computation 831 * 832 * digest may be same as text or key 833 */ 834 void hmac_md5(const unsigned char *text, int text_len, 835 const unsigned char *key, int key_len, 836 unsigned char digest[HMAC_MD5_SIZE]); 838 /* create context from key 839 */ 840 void hmac_md5_init(HMAC_MD5_CTX *hmac, 841 const unsigned char *key, int key_len); 843 /* precalculate intermediate state from key 844 */ 846 void hmac_md5_precalc(HMAC_MD5_STATE *hmac, 847 const unsigned char *key, int key_len); 849 /* initialize context from intermediate state 850 */ 851 void hmac_md5_import(HMAC_MD5_CTX *hmac, HMAC_MD5_STATE *state); 853 #define hmac_md5_update(hmac, text, text_len) \ 854 MD5Update(&(hmac)->ictx, (text), (text_len)) 856 /* finish hmac from intermediate result. 857 * Intermediate result is erased. 858 */ 859 void hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE], 860 HMAC_MD5_CTX *hmac); 862 /* hmac-md5.c -- HMAC MD5 Keyed-Hashing by Chris Newman 863 * derived from RFC 2104 by H. Krawczyk, M. Bellare, R.Canetti 864 */ 865 #include 866 #include 867 #include "md5.h" 868 #include "hmac-md5.h" 870 /* for htonl() and ntohl() */ 871 #include 872 #include 874 /* MD5 block size */ 875 #define BLOCK_SIZE 64 877 void hmac_md5_init(HMAC_MD5_CTX *hmac, 878 const unsigned char *key, int key_len) 879 { 880 unsigned char k_pad[BLOCK_SIZE]; /* padded key */ 881 int i; 883 /* if key longer than BLOCK_SIZE bytes reset to MD5(key) */ 884 if (key_len > BLOCK_SIZE) { 885 MD5Init(&hmac->ictx); 886 MD5Update(&hmac->ictx, key, key_len); 887 MD5Final(k_pad, &hmac->ictx); 888 key = k_pad; 889 key_len = HMAC_MD5_SIZE; 890 } 892 /* XOR padded key with inner pad value */ 893 for (i = 0; i < key_len; i++) { 894 k_pad[i] = key[i] ^ 0x36; 895 } 896 while (i < BLOCK_SIZE) { 897 k_pad[i++] = 0x36; 898 } 900 /* Begin inner MD5 */ 901 MD5Init(&hmac->ictx); 902 MD5Update(&hmac->ictx, k_pad, BLOCK_SIZE); 904 /* XOR padded key with outer pad value */ 905 for (i = 0; i < BLOCK_SIZE; ++i) { 906 k_pad[i] ^= (0x36 ^ 0x5c); 907 } 909 /* Begin outer MD5 */ 910 MD5Init(&hmac->octx); 911 MD5Update(&hmac->octx, k_pad, BLOCK_SIZE); 913 /* clean up workspace */ 914 memset(k_pad, 0, BLOCK_SIZE); 915 } 917 void hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE], 918 HMAC_MD5_CTX *hmac) 919 { 920 /* finish inner MD5 */ 921 MD5Final(digest, &hmac->ictx); 922 /* finish outer MD5 */ 923 MD5Update(&hmac->octx, digest, HMAC_MD5_SIZE); 924 MD5Final(digest, &hmac->octx); 925 /* MD5Final zeros context */ 926 } 928 void hmac_md5(const unsigned char *text, int text_len, 929 const unsigned char *key, int key_len, 930 unsigned char digest[HMAC_MD5_SIZE]) 931 { 932 HMAC_MD5_CTX hmac; 934 hmac_md5_init(&hmac, key, key_len); 935 hmac_md5_update(&hmac, text, text_len); 936 hmac_md5_final(digest, &hmac); 937 } 939 void hmac_md5_precalc(HMAC_MD5_STATE *ctx, 940 const unsigned char *pass, int passlen) 942 { 943 HMAC_MD5_CTX hctx; 945 if (passlen == 0) passlen = strlen((const char *) pass); 946 hmac_md5_init(&hctx, pass, passlen); 947 ctx->istate[0] = htonl(hctx.ictx.state[0]); 948 ctx->istate[1] = htonl(hctx.ictx.state[1]); 949 ctx->istate[2] = htonl(hctx.ictx.state[2]); 950 ctx->istate[3] = htonl(hctx.ictx.state[3]); 951 ctx->ostate[0] = htonl(hctx.octx.state[0]); 952 ctx->ostate[1] = htonl(hctx.octx.state[1]); 953 ctx->ostate[2] = htonl(hctx.octx.state[2]); 954 ctx->ostate[3] = htonl(hctx.octx.state[3]); 955 memset(&hctx, 0, sizeof (hctx)); 956 } 958 void hmac_md5_import(HMAC_MD5_CTX *hctx, HMAC_MD5_STATE *ctx) 959 { 960 hctx->ictx.state[0] = ntohl(ctx->istate[0]); 961 hctx->ictx.state[1] = ntohl(ctx->istate[1]); 962 hctx->ictx.state[2] = ntohl(ctx->istate[2]); 963 hctx->ictx.state[3] = ntohl(ctx->istate[3]); 964 hctx->octx.state[0] = ntohl(ctx->ostate[0]); 965 hctx->octx.state[1] = ntohl(ctx->ostate[1]); 966 hctx->octx.state[2] = ntohl(ctx->ostate[2]); 967 hctx->octx.state[3] = ntohl(ctx->ostate[3]); 968 hctx->ictx.count[0] = hctx->octx.count[0] = BLOCK_SIZE << 3; 969 hctx->ictx.count[1] = hctx->octx.count[1] = 0; 970 } 972 C. Appendix - SCRAM sample source code 974 The following sample source code implements SCRAM itself for both 975 server and client. 977 Please note the lines marked "XXX: ..." as they need to be 978 translated from English to computer readable code. 980 A client implementation simply calls scram_md5_generate() with the 981 passphrase after receiving the first server reply. The cproof 982 parameter will hold the message to send to the server and the 983 sproof parameter will hold the expected server mutual 984 authentication. The clidata parameter holds the client's security 985 layer selections. A client may also call hmac_md5_precalc() to 986 turn a passphrase into CRAM/SCRAM credentials for later use in 987 scram_md5_generate(). 989 A server implementation simply calls scram_md5_generate() with the 990 stored verifier, the second client message and the SCRAM_VERIFY 991 option. Server verifiers are generated by creating a random salt 992 and calling scram_md5_vgen() with either the passphrase or 993 CRAM/SCRAM credentials. 995 If integrity protection is desired, the integrity_key parameter may 996 be provided to scram_md5_generate() and will receive the resulting 997 key. Generating an verifying the integrity protection is left as 998 an exercise to the reader. 1000 /* scram.h -- scram utility functions 1001 */ 1002 /* size of SCRAM_MD5 salt and verifier */ 1003 #define SCRAM_MD5_SALTSIZE 8 1004 #define SCRAM_MD5_DATASIZE 16 1006 /* SCRAM verifier */ 1007 typedef struct SCRAM_MD5_VRFY_s { 1008 unsigned char salt[SCRAM_MD5_SALTSIZE]; 1009 unsigned char clidata[SCRAM_MD5_DATASIZE]; 1010 unsigned char svrdata[SCRAM_MD5_DATASIZE]; 1011 } SCRAM_MD5_VRFY; 1013 /* Client proof message */ 1014 typedef struct SCRAM_MD5_CLIENT_s { 1015 unsigned char secprops[4]; 1016 unsigned char cproof[SCRAM_MD5_DATASIZE]; 1017 } SCRAM_MD5_CLIENT; 1019 /* generate SCRAM-MD5 verifier 1020 * vptr -- gets result 1021 * salt -- contains salt of SCRAM_MD5_SALTSIZE 1022 * pass -- passphrase or verifier 1023 * passlen -- len of pass/verifier (0 ok if NUL terminated) 1024 * plainflag -- 1 = plaintext passphrase, 1025 * 0 = result of hmac_md5_precalc() 1026 * clientkey -- cache for client proof, usually NULL 1027 */ 1028 void scram_md5_vgen(SCRAM_MD5_VRFY *vptr, 1029 const unsigned char *salt, 1030 const char *pass, int passlen, int plainflag, 1031 unsigned char *clientkey); 1033 /* scram secret action type */ 1034 #define SCRAM_CREDENTIAL 0 /* generate replies using credentials */ 1035 #define SCRAM_PLAINTEXT 1 /* generate replies using plaintext */ 1036 #define SCRAM_VERIFY 2 /* use SCRAM_MD5_VRFY to verify client, 1037 and generate server reply */ 1039 /* generate or verify SCRAM-MD5 1040 * input params: 1041 * cchal -- client challenge string 1042 * cchallen -- length of client challenge 1043 * schal -- server challenge string 1044 * schallen -- length of server challenge 1045 * secret -- passphrase, credentials, or verifier 1046 * secretlen -- length of passphrase (0 ok if NUL terminated) 1047 * action -- see above 1048 * in/out: 1049 * clidata -- client data for client response 1050 * output: 1051 * sproof -- server proof of length SCRAM_MD5_DATASIZE 1052 * integrity_key -- integrity key of length SCRAM_MD5_DATASIZE 1053 * caller may pass NULL if no integrity needed 1054 * returns: 1055 * -2 if params invalid 1056 * -1 if verify fails 1057 * 0 on success 1058 */ 1059 int scram_md5_generate(const char *cchal, int cchallen, 1060 const char *schal, int schallen, 1061 const char *secret, int secretlen, 1062 int action, 1063 SCRAM_MD5_CLIENT *clidata, 1064 unsigned char *sproof, 1065 unsigned char *integrity_key); 1067 /* scram.c -- routines for SCRAM-MD5 calculations 1068 */ 1069 #include 1070 #include 1071 #include 1072 #include "md5.h" 1073 #include "hmac-md5.h" 1074 #include "scram.h" 1076 void scram_md5_vgen(SCRAM_MD5_VRFY *vptr, 1077 const unsigned char *salt, 1078 const char *pass, int passlen, int plainflag, 1079 unsigned char *clientkey) 1080 { 1081 HMAC_MD5_CTX hctx; 1083 if (clientkey == NULL) clientkey = vptr->clidata; 1084 /* get context */ 1085 if (plainflag) { 1086 if (passlen == 0) passlen = strlen(pass); 1087 hmac_md5_init(&hctx, (const unsigned char *) pass, 1088 passlen); 1089 } else { 1090 hmac_md5_import(&hctx, (HMAC_MD5_STATE *) pass); 1091 } 1093 /* generate salted passphrase */ 1094 hmac_md5_update(&hctx, salt, SCRAM_MD5_SALTSIZE); 1095 hmac_md5_final(vptr->clidata, &hctx); 1097 /* generate server proof */ 1098 hmac_md5(salt, SCRAM_MD5_SALTSIZE, vptr->clidata, 1099 sizeof (vptr->clidata), vptr->svrdata); 1101 /* generate client key and client verifier */ 1102 MD5Init(&hctx.ictx); 1103 MD5Update(&hctx.ictx, vptr->clidata, sizeof (vptr->clidata)); 1104 MD5Final(clientkey, &hctx.ictx); 1105 MD5Init(&hctx.ictx); 1106 MD5Update(&hctx.ictx, clientkey, SCRAM_MD5_DATASIZE); 1107 MD5Final(vptr->clidata, &hctx.ictx); 1109 /* copy salt to verifier */ 1110 if (salt != vptr->salt) { 1111 memcpy(vptr->salt, salt, SCRAM_MD5_SALTSIZE); 1112 } 1113 } 1115 int scram_md5_generate(const char *cchal, int cchallen, 1116 const char *schal, int schallen, 1117 const char *secret, int secretlen, 1118 int action, 1119 SCRAM_MD5_CLIENT *clidata, 1120 unsigned char *sproof, 1121 unsigned char *integrity_key) 1122 { 1123 SCRAM_MD5_VRFY verifier, *vptr; 1124 HMAC_MD5_CTX hctx; 1125 unsigned char clientkey[HMAC_MD5_SIZE]; 1126 unsigned char sharedkey[HMAC_MD5_SIZE]; 1127 int i, result = 0; 1129 /* check params */ 1130 if ((action == SCRAM_CREDENTIAL 1131 && secretlen != sizeof (HMAC_MD5_STATE)) 1132 || (action == SCRAM_VERIFY 1133 && secretlen != sizeof (verifier)) 1134 || schallen < SCRAM_MD5_SALTSIZE) { 1135 return (-2); 1136 } 1138 /* get verifier */ 1139 if (action == SCRAM_VERIFY) { 1140 vptr = (SCRAM_MD5_VRFY *) secret; 1141 } else { 1142 scram_md5_vgen(&verifier, (const unsigned char *) schal, 1143 secret, secretlen, action, clientkey); 1144 vptr = &verifier; 1145 } 1147 /* calculate shared key */ 1148 hmac_md5_init(&hctx, vptr->clidata, sizeof (vptr->clidata)); 1149 hmac_md5_update(&hctx, (unsigned char *) schal, schallen); 1150 hmac_md5_update(&hctx, (unsigned char *) cchal, cchallen); 1151 hmac_md5_update(&hctx, clidata->secprops, 4); 1152 hmac_md5_final(sharedkey, &hctx); 1154 if (action == SCRAM_VERIFY) { 1155 /* verify client proof */ 1156 for (i = 0; i < HMAC_MD5_SIZE; ++i) { 1157 XXX: the line which belongs here is omitted due to 1158 U.S. export regulations, but it exclusive-ors the 1159 "sharedkey" with the "clidata->cproof" and places the 1160 result in "clientkey" (see step (c) above) 1161 } 1162 MD5Init(&hctx.ictx); 1163 MD5Update(&hctx.ictx, clientkey, sizeof (clientkey)); 1164 MD5Final(sharedkey, &hctx.ictx); 1165 if (memcmp(sharedkey, vptr->clidata, 1166 sizeof (sharedkey)) != 0) { 1167 result = -1; 1168 } 1169 } else { 1170 /* generate client proof */ 1171 for (i = 0; i < HMAC_MD5_SIZE; ++i) { 1172 XXX: the line which belongs here is omitted due to 1173 U.S. export regulations, but it exclusive-ors the 1174 "sharedkey" with the "clientkey" and places the 1175 result in "clidata->cproof" (see step (G) above) 1176 } 1177 } 1178 /* calculate integrity key */ 1179 if (integrity_key != NULL) { 1180 hmac_md5_init(&hctx, clientkey, HMAC_MD5_SIZE); 1181 hmac_md5_update(&hctx, (unsigned char *) schal, schallen); 1182 hmac_md5_update(&hctx, (unsigned char *) cchal, cchallen); 1183 hmac_md5_update(&hctx, clidata->secprops, 4); 1184 hmac_md5_final(integrity_key, &hctx); 1185 } 1187 /* calculate server result */ 1188 if (result == 0) { 1189 hmac_md5_init(&hctx, vptr->svrdata, HMAC_MD5_SIZE); 1190 hmac_md5_update(&hctx, (unsigned char *) cchal, cchallen); 1191 hmac_md5_update(&hctx, (unsigned char *) schal, schallen); 1192 hmac_md5_update(&hctx, clidata->secprops, 4); 1193 hmac_md5_final(sproof, &hctx); 1194 } 1196 /* cleanup workspace */ 1197 memset(clientkey, 0, sizeof (clientkey)); 1198 memset(sharedkey, 0, sizeof (sharedkey)); 1199 if (vptr == &verifier) memset(&verifier, 0, sizeof (verifier)); 1201 return (result); 1202 }