RFC 8265

Preparation, Enforcement, and Comparison of Internationalized Strings Representing Usernames and Passwords

πŸ“… published October 2017, from ietf

RFC 8265 πŸŽ€

Preparation, Enforcement, and Comparison of Internationalized Strings Representing Usernames and Passwords πŸ’–

Authors: P. Saint-Andre (Jabber.org) and A. Melnikov (Isode Ltd) πŸ‘‘

Category: Standards Track πŸ†

Date: October 2017 πŸ“…

Obsoletes: RFC 7613 πŸ”

ISSN: 2070-1721 🌈

Internet Engineering Task Force (IETF) 🌸


Abstract πŸ’œ

okay so this doc is all about updated ways to handle Unicode strings for usernames and passwords πŸ’… The old approach was called SASLprep (RFC 4013), which was built on Stringprep (RFC 3454). The methods in here are a more sustainable way to handle internationalized usernames and passwords ✨ This document obsoletes RFC 7613. πŸ¦‹

Status of This Memo πŸ“œ

bestie this is an Internet Standards Track document πŸ†

It's an official IETF product. It represents the consensus of the IETF community, it got public review, and the Internet Engineering Steering Group (IESG) signed off on it for publication. More on Internet Standards lives in Section 2 of RFC 7841 πŸ”

Want the latest on this doc, its errata, or how to send feedback? Check https://www.rfc-editor.org/info/rfc8265 πŸ”—

Legal bit, but make it cute: the IETF Trust and the people listed as authors own the copyright (c) 2017, and all rights are reserved πŸ’œ

This doc is covered by BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info), as they stood on the publication date. Read those carefully, because they spell out your rights and restrictions πŸ“–

Any Code Components pulled out of this doc have to include Simplified BSD License text, as described in Section 4.e of the Trust Legal Provisions, and they come with no warranty, per the Simplified BSD License 🚫⚠️

Table of Contents πŸ“š

1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   3
2.  Terminology . . . . . . . . . . . . . . . . . . . . . . . . .   4
3.  Usernames . . . . . . . . . . . . . . . . . . . . . . . . . .   5
  3.1.  Definition  . . . . . . . . . . . . . . . . . . . . . . .   5
  3.2.  Case Mapping vs. Case Preservation  . . . . . . . . . . .   6
  3.3.  UsernameCaseMapped Profile  . . . . . . . . . . . . . . .   7
    3.3.1.  Rules . . . . . . . . . . . . . . . . . . . . . . . .   7
    3.3.2.  Preparation . . . . . . . . . . . . . . . . . . . . .   8
    3.3.3.  Enforcement . . . . . . . . . . . . . . . . . . . . .   8
    3.3.4.  Comparison  . . . . . . . . . . . . . . . . . . . . .   9
  3.4.  UsernameCasePreserved Profile . . . . . . . . . . . . . .   9
    3.4.1.  Rules . . . . . . . . . . . . . . . . . . . . . . . .   9
    3.4.2.  Preparation . . . . . . . . . . . . . . . . . . . . .   9
    3.4.3.  Enforcement . . . . . . . . . . . . . . . . . . . . .  10
    3.4.4.  Comparison  . . . . . . . . . . . . . . . . . . . . .  10
  3.5.  Application-Layer Constructs  . . . . . . . . . . . . . .  11
  3.6.  Examples  . . . . . . . . . . . . . . . . . . . . . . . .  11
4.  Passwords . . . . . . . . . . . . . . . . . . . . . . . . . .  13
  4.1.  Definition  . . . . . . . . . . . . . . . . . . . . . . .  13
  4.2.  OpaqueString Profile  . . . . . . . . . . . . . . . . . .  14
    4.2.1.  Preparation . . . . . . . . . . . . . . . . . . . . .  14
    4.2.2.  Enforcement . . . . . . . . . . . . . . . . . . . . .  14
    4.2.3.  Comparison  . . . . . . . . . . . . . . . . . . . . .  15
  4.3.  Examples  . . . . . . . . . . . . . . . . . . . . . . . .  15
5.  Use in Application Protocols  . . . . . . . . . . . . . . . .  16
6.  Migration . . . . . . . . . . . . . . . . . . . . . . . . . .  17
  6.1.  Usernames . . . . . . . . . . . . . . . . . . . . . . . .  17
  6.2.  Passwords . . . . . . . . . . . . . . . . . . . . . . . .  19
7.  IANA Considerations . . . . . . . . . . . . . . . . . . . . .  20
  7.1.  UsernameCaseMapped Profile  . . . . . . . . . . . . . . .  20
  7.2.  UsernameCasePreserved Profile . . . . . . . . . . . . . .  20
  7.3.  OpaqueString Profile  . . . . . . . . . . . . . . . . . .  21
  7.4.  Stringprep Profile  . . . . . . . . . . . . . . . . . . .  22
8.  Security Considerations . . . . . . . . . . . . . . . . . . .  22
  8.1.  Password/Passphrase Strength  . . . . . . . . . . . . . .  22
  8.2.  Password/Passphrase Comparison  . . . . . . . . . . . . .  22
  8.3.  Identifier Comparison . . . . . . . . . . . . . . . . . .  22
  8.4.  Reuse of PRECIS . . . . . . . . . . . . . . . . . . . . .  22
  8.5.  Reuse of Unicode  . . . . . . . . . . . . . . . . . . . .  22
9.  References  . . . . . . . . . . . . . . . . . . . . . . . . .  23
  9.1.  Normative References  . . . . . . . . . . . . . . . . . .  23
  9.2.  Informative References  . . . . . . . . . . . . . . . . .  24
Appendix A.  Changes from RFC 7613  . . . . . . . . . . . . . . .  25
Acknowledgements  . . . . . . . . . . . . . . . . . . . . . . . .  26
Authors' Addresses  . . . . . . . . . . . . . . . . . . . . . . .  26

1. Introduction ✨

Usernames and passwords are everywhere on the Internet for authentication and authorization πŸ” Sometimes they travel in plaintext, like with the PLAIN Simple Authentication and Security Layer (SASL) mechanism [RFC4616] and the HTTP Basic scheme [RFC7617]. Other times they get fed into a cryptographic algorithm, like a hash function, as in the Salted Challenge Response Authentication Mechanism (SCRAM) SASL mechanism [RFC5802] and the HTTP Digest scheme [RFC7616].

So that typing and comparing usernames and passwords makes sense for people all over the world 🌍, this document sets rules for handling internationalized strings that represent them. These strings are made of code points from the Unicode coded character set [Unicode], with extra attention paid to code points outside the ASCII range [RFC20]. The rules are spelled out as profiles of the string classes from the preparation, enforcement, and comparison of internationalized strings (PRECIS) framework specification [RFC8264] πŸ’œ

PRECIS profiles let software handle non-ASCII Unicode code points automatically, so they get treated carefully and consistently across application protocols. Mostly these profiles protect app developers from the risks of supporting the whole Unicode range πŸ›‘οΈ For example, in almost every application protocol, treating ΒΉ (SUPERSCRIPT ONE, U+00B9) as equivalent to 1 (DIGIT ONE, U+0031) would be dangerous πŸ™ˆ It would cause false accepts during comparison, authentication, and authorization. An attacker could easily spoof the account user1@example.com. 😱

Without a careful approach, naive Unicode use would make attacks trivially easy 😈, but the username profile defined here generally keeps applications from causing these problems by accident. (Passwords have similar concerns, but there it's actually desirable to support a wider range of characters, so you get more entropy for authentication πŸ”‘.)

The methods here might apply anywhere usernames or passwords show up. They're not meant for strings that aren't usernames, like Lightweight Directory Access Protocol (LDAP) distinguished names πŸ™…. They're also not meant for cases where identifiers or secrets aren't strings, like keys and certificates, or where they need specialized handling.

The historical ancestor of this doc was the SASLprep profile of Stringprep [RFC3454], but the approach here can be used by technologies other than SASL [RFC4422], like HTTP authentication as specified in [RFC7617] and [RFC7616] 🌸

πŸ›‘ Big note: this document doesn't change how existing application protocols that use SASLprep handle internationalized strings in usernames and passwords. If a community wants to modernize and move from Stringprep to PRECIS, it has to explicitly update that application protocol's definition (one example is [RFC7622]). Uncoordinated updates to protocol implementations are discouraged, since they can hurt interoperability and security πŸ’€

2. Terminology πŸ“–

A "username" or "user identifier" is a string of characters that designates an account on a computing device or system πŸ§‘β€πŸ’», often but not necessarily for a person to use. Sure, some devices let a username be part or all of a person's name, and people might want their account designator to match their name. But because of the complexities involved, that isn't guaranteed for every human name on every device or system that follows these rules πŸ₯Ί Protocol designers and app developers who want to allow a wider range of characters are encouraged to separate more restrictive account identifiers from more expressive display names or nicknames (see [RFC8266]) πŸ¦‹

A "password" is a string of characters that allows access to a computing device or system, often tied to a particular username πŸ” It's not literally limited to a single word, since a password could be a passphrase made of several words, perhaps separated by spaces, punctuation, or other non-alphanumeric characters ✨

Some SASL mechanisms (e.g., CRAM-MD5, DIGEST-MD5, and SCRAM) say that the authentication identity used in those mechanisms is a "simple username" (see Section 2 of [RFC4422] as well as [RFC4013]). Lots of application technologies also assume a user's identity takes the form of a username (like authentication for the Hypertext Transfer Protocol as specified in [RFC7617] and [RFC7616]), whether or not they use SASL 🌈 Note well: the exact form of a username in any particular SASL mechanism or application technology is up to implementation and deployment πŸ‘€ A username also doesn't necessarily map to any particular application identifier.

Lots of important terms in this doc are defined in [RFC5890], [RFC6365], [RFC8264], and [Unicode] πŸ“š The term "non-ASCII space" refers to any Unicode code point with a Unicode general category of Zs 🌟, naturally except for SPACE (U+0020) πŸ™„

Okay, the key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are read as described in BCP 14 [RFC2119] [RFC8174], but only when they appear in all capitals, just like here πŸ’…

3. Usernames πŸŽ€

Part 1 ends right here, bestie! πŸ’– Part 2 picks up with Section 3, so stay tuned 🧚

3.1. Definition

okay so bestie, this is the big one ✨. A username is a string of Unicode code points [Unicode] structured as an ordered sequence of "userparts", written in a standard Unicode Encoding Form (such as UTF-8 [RFC3629]). Every userpart can only hold code points that the PRECIS IdentifierClass from Section 4.2 of [RFC8264] allows, which is why it's almost totally letters and digits 🌸. A username can be one userpart on its own, or a bunch of userparts separated by spaces πŸ’–.

Here's the grammar, written in Augmented Backus-Naur Form (ABNF) [RFC5234] πŸŽ€:

username   = userpart *(1*SP userpart)
userpart   = 1*(idpoint)
             ;
             ; an "idpoint" is a Unicode code point that
             ; can be contained in a string conforming to
             ; the PRECIS IdentifierClass
             ;

Anything the IdentifierClass doesn't explicitly allow is out, no exceptions πŸ™…β€β™€οΈ. That includes private-use code points, surrogate code points, and all the other code points and blocks that were called "Prohibited Output" in Section 2.3 of [RFC4013] (once they're corrected per [Err1812]). The one plot twist is that common constructions like user@example.com (for example, the Network Access Identifier from [RFC7542]) are still allowed as usernames under this spec, same as they were under [RFC4013] πŸ¦‹.

Implementation Note: Don't assume this definition matches everything your deployed apps call a "username" or "userid" πŸ™ˆ. This is really a relatively safe subset of Unicode code points that works with existing SASL mechanisms, with application protocols that use SASL, and even with plenty of application protocols that don't use SASL yet πŸ’….

A username MUST NOT be zero bytes in length. This rule gets enforced after any normalization and mapping of code points, so nothing sneaks past it πŸ‘‘.

This spec defines two profiles for usernames: the UsernameCaseMapped profile does case mapping, and the UsernameCasePreserved profile does case preservation. (There's more tea on that in Section 3.2 πŸ“.)

In protocols that feed usernames into a cryptographic algorithm, like a hash function, the client will need to enforce the rules for the UsernameCaseMapped or UsernameCasePreserved profile before it applies the algorithm πŸ”.


3.2. Case Mapping vs. Case Preservation

So to fit the widest range of username setups in apps, this document defines two profiles: UsernameCaseMapped and UsernameCasePreserved. The only real difference between them is whether they use the Case Mapping Rule, and otherwise they're identical πŸ’œ.

Case mapping is up to the application protocol, the protocol implementation, or the end deployment. In general this document suggests that UsernameCaseMapped is the better pick, so you do case mapping. Skipping it can lead to false accepts during authentication and authorization (as described in [RFC6943]), and it can confuse end users, since so many existing protocols and apps already do case mapping πŸ€”. That said, there can be good reasons to go with UsernameCasePreserved and skip case mapping, like backward compatibility with infrastructure that's already out there πŸ› οΈ.

Here's the breakdown:

  • SASL mechanisms that follow the recommendations in this document MUST specify whether and when case mapping is applied to authentication identifiers. Case mapping loses information, so implementations SHOULD delay any case mapping until the last possible moment to keep that info around as long as possible. That moment is things like doing a lookup by username, comparing usernames, or generating a cryptographic salt from a username. (If the last possible moment happens on a server, then case mapping decisions can just be a matter of service deployment policy 🧁.) Following [RFC4422], SASL mechanisms aren't allowed to apply this or any other profile to authorization identifiers, only to authentication identifiers 🚫.
  • Application protocols that use SASL (like IMAP [RFC3501] and the Extensible Messaging and Presence Protocol (XMPP) [RFC6120]) and that directly reuse this profile MUST specify whether or not case mapping is applied to authorization identifiers. These "SASL application protocols" SHOULD delay any case mapping of authorization identifiers to the last possible moment, which always ends up being on the server side. (That way, case mapping decisions are a matter of service deployment policy ✨.) Following [RFC4422] again, SASL application protocols aren't allowed to apply this or any other profile to authentication identifiers, only to authorization identifiers πŸ’….
  • Application protocols that don't use SASL (like HTTP authentication with the HTTP Basic and Digest schemes in [RFC7617] and [RFC7616]) but that directly reuse this profile MUST specify whether and when case mapping is applied to authentication identifiers, authorization identifiers, or both 🌈. These "non-SASL application protocols" SHOULD delay any case mapping to the last possible moment, like doing a lookup by username, comparing usernames, or generating a cryptographic salt from a username. (If that last moment happens on the server, case mapping decisions can be a matter of service deployment policy 🫢.)

If the spec for a SASL mechanism, a SASL application protocol, or a non-SASL application protocol uses the UsernameCaseMapped profile, it MUST clearly describe whether case mapping is applied at the level of the protocol itself, its implementations, or service deployments. Each of those approaches can be legit, depending on the app you're building πŸ‘‘.


3.3. UsernameCaseMapped Profile

3.3.1. Rules

These rules are defined for use within the UsernameCaseMapped profile of the PRECIS IdentifierClass πŸ¦‹.

  1. Width Mapping Rule: Map fullwidth and halfwidth code points to their decomposition mappings (see Unicode Standard Annex #11 [UAX11]).
  2. Additional Mapping Rule: There is no additional mapping rule. Nothing extra here, bestie πŸ™Œ.
  3. Case Mapping Rule: Map uppercase and titlecase code points to their lowercase equivalents, preferably using the Unicode toLowerCase() operation as defined in the Unicode Standard [Unicode]. See further discussion in Section 3.2 πŸ“š.
  4. Normalization Rule: Apply Unicode Normalization Form C (NFC) to all strings πŸ’Ž.
  5. Directionality Rule: Apply the "Bidi Rule" defined in [RFC5893] to strings that contain right-to-left code points (so each of the six conditions of the Bidi Rule must be satisfied). For strings that don't contain right-to-left code points, there's no special directionality processing 🧭.

3.3.2. Preparation

An entity that prepares an input string for later enforcement under this profile MUST go through these steps, in the order shown πŸ“.

  1. Apply the width mapping rule specified in Section 3.3.1. This has to happen at this point, because otherwise the PRECIS "HasCompat" category specified in Section 9.17 of [RFC8264] would forbid fullwidth and halfwidth code points 🚫.
  2. Make sure the string only has Unicode code points that are explicitly allowed by the PRECIS IdentifierClass defined in Section 4.2 of [RFC8264] βœ….

3.3.3. Enforcement

An entity that enforces this profile MUST prepare an input string as described in Section 3.3.2, and MUST also apply the following rules from Section 3.3.1, in the order shown πŸ”₯:

  1. Case Mapping Rule
  2. Normalization Rule
  3. Directionality Rule

After all of those rules have been enforced, the entity MUST make sure the username is not zero bytes in length. This check happens last so applications don't accidentally skip the username entirely. When internationalized strings are accepted, a non-empty sequence of characters can end up as a zero-length username after canonicalization 😭.

The result of all that is an output string that conforms to the UsernameCaseMapped profile. Until an implementation produces such an output string, it MUST NOT treat the string as conforming. (In particular, it MUST NOT assume an input string is conforming before enforcement has finished πŸ™…β€β™€οΈ.)

3.3.4. Comparison

An entity that compares two strings under this profile MUST prepare each string as specified in Section 3.3.2, and then MUST enforce the rules in Section 3.3.3. The two strings are equivalent if and only if they're an exact octet-for-octet match (sometimes called "bit-string identity") πŸ’œ.

Until an implementation decides whether two strings are equivalent, it MUST NOT treat them as equivalent. (In particular, it MUST NOT assume two input strings are equivalent before the comparison has been completed 🫠.)


3.4. UsernameCasePreserved Profile

3.4.1. Rules

These rules are defined for use within the UsernameCasePreserved profile of the PRECIS IdentifierClass πŸŽ€.

  1. Width Mapping Rule: Map fullwidth and halfwidth code points to their decomposition mappings (see Unicode Standard Annex #11 [UAX11]).
  2. Additional Mapping Rule: There is no additional mapping rule.
  3. Case Mapping Rule: There is no case mapping rule. Case stays exactly as it was typed 🌸.
  4. Normalization Rule: Apply Unicode Normalization Form C (NFC) to all strings.
  5. Directionality Rule: Apply the "Bidi Rule" defined in [RFC5893] to strings that contain right-to-left code points (so each of the six conditions of the Bidi Rule must be satisfied). For strings that don't contain right-to-left code points, there's no special directionality processing.

3.4.2. Preparation

An entity that prepares a string for later enforcement under this profile MUST go through these steps, in the order shown ✨.

  1. Apply the width mapping rule specified in Section 3.4.1. This has to happen here, because otherwise the PRECIS "HasCompat" category specified in Section 9.17 of [RFC8264] would forbid fullwidth and halfwidth code points πŸ’–.
  2. Make sure the string only has Unicode code points that are explicitly allowed by the PRECIS IdentifierClass defined in Section 4.2 of [RFC8264] πŸ¦‹.

3.4.3. Enforcement ✨

okay so, an entity enforcing this profile MUST prepare the string the way Section 3.4.2 describes, and it MUST also apply the rules from Section 3.4.1 in this exact order: πŸŽ€

  1. Normalization Rule
  2. Directionality Rule

once all of that is done, the entity MUST ensure the username is not zero bytes in length. this check goes last on purpose so apps don't accidentally drop a username entirely 😭 (with internationalized strings, a non-empty run of characters can turn into a zero-length username after canonicalization, so it's a real trap πŸ’€)

the result is an output string that conforms to the UsernameCasePreserved profile πŸ’–. until an implementation actually produces that output string, it MUST NOT treat the string as conforming. (in particular, it MUST NOT assume an input string is conforming before enforcement is finished πŸ™ˆ)

3.4.4. Comparison πŸ’œ

an entity comparing two strings under this profile MUST prepare each string as specified in Section 3.4.2, and then MUST enforce the rules in Section 3.4.3. the two strings count as equivalent if and only if they're an exact octet-for-octet match, which is sometimes called "bit-string identity" 🧚

until an implementation has figured out whether two strings are equivalent, it MUST NOT treat them as equivalent. (in particular, it MUST NOT assume two input strings are equivalent before the comparison is done 🫢)

3.5. Application-Layer Constructs 🌈

both the UsernameCaseMapped and UsernameCasePreserved profiles let an application protocol, implementation, or deployment build application-layer constructs, like a username that's a space-separated set of userparts such as "Firstname Middlename Lastname" πŸ“

this isn't a profile of the PRECIS IdentifierClass, because SPACE (U+0020) isn't allowed in the IdentifierClass πŸ™…β€β™€οΈ. BUT it can still be created at the application layer, because SPACE (U+0020) can be used as a separator between instances of the PRECIS IdentifierClass (e.g., userparts as defined in this specification) ✨

3.6. Examples πŸ¦‹

these examples show a few userparts (not usernames) that fit the format we just talked about. (the "<" and ">" characters are only here to mark where each userpart starts and ends. they aren't part of the userpart strings πŸ’…)

+--------------------------+---------------------------------+
| # | Userpart             | Notes                           |
+--------------------------+---------------------------------+
| 1 | <juliet@example.com> | The "at" sign ("@") is allowed  |
|   |                      | in the PRECIS IdentifierClass   |
+--------------------------+---------------------------------+
| 2 | <fussball>           |                                 |
+--------------------------+---------------------------------+
| 3 | <fußball>            | The third character is LATIN    |
|   |                      | SMALL LETTER SHARP S (U+00DF)   |
+--------------------------+---------------------------------+
| 4 | <Ο€>                  | A userpart of GREEK SMALL       |
|   |                      | LETTER PI (U+03C0)              |
+--------------------------+---------------------------------+
| 5 | <Ξ£>                  | A userpart of GREEK CAPITAL     |
|   |                      | LETTER SIGMA (U+03A3)           |
+--------------------------+---------------------------------+
| 6 | <Οƒ>                  | A userpart of GREEK SMALL       |
|   |                      | LETTER SIGMA (U+03C3)           |
+--------------------------+---------------------------------+
| 7 | <Ο‚>                  | A userpart of GREEK SMALL       |
|   |                      | LETTER FINAL SIGMA (U+03C2)     |
+--------------------------+---------------------------------+

                 Table 1: A Sample of Legal Userparts

okay so about examples 2 and 3 πŸ₯¨: in German writing, the eszett "ß" (LATIN SMALL LETTER SHARP S, U+00DF) can mostly be swapped with the two characters "ss". but these userparts are still different, so (if you want) a server would need to enforce a registration policy that blocks one of them if the other is already registered πŸ”’

and for examples 5, 6, and 7 πŸ’«: optional case mapping of "Ξ£" (GREEK CAPITAL LETTER SIGMA, U+03A3) to the lowercase "Οƒ" (GREEK SMALL LETTER SIGMA, U+03C3) during comparison would make the userparts in examples 5 and 6 match. however, the PRECIS mapping rules don't account for the special status of "Ο‚" (GREEK SMALL LETTER FINAL SIGMA, U+03C2), so examples 5 and 7, or examples 6 and 7, would NOT match during comparison 😭

next up are strings that are NOT valid userparts (not usernames) because they break the format above 🚫

+--------------------------+---------------------------------+
| # | Non-Userpart String  | Notes                           |
+--------------------------+---------------------------------+
| 8 | <foo bar>            | SPACE (U+0020) is disallowed in |
|   |                      | the userpart                    |
+--------------------------+---------------------------------+
| 9 | <>                   | Zero-length userpart            |
+--------------------------+---------------------------------+
| 10| <henryβ…£>            | The sixth character is ROMAN    |
|   |                      | NUMERAL FOUR (U+2163)           |
+--------------------------+---------------------------------+
| 11| <∞>                  | A userpart of INFINITY (U+221E) |
+--------------------------+---------------------------------+

 Table 2: A Sample of Strings That Violate the Userpart Rules

example 8 is a bit of a plot twist 🎭: it's not a valid userpart, BUT it IS a valid username, because it's a space-separated sequence of userparts ✨

example 10: the character "β…£" (ROMAN NUMERAL FOUR, U+2163) has a compatibility equivalent of "I" (LATIN CAPITAL LETTER I, U+0049) and "V" (LATIN CAPITAL LETTER V, U+0056). but code points with compatibility equivalents aren't allowed in the PRECIS IdentifierClass, so no dice πŸ™…β€β™€οΈ

example 11: symbols like "∞" (INFINITY, U+221E) aren't allowed in the PRECIS IdentifierClass either πŸ’€

4. Passwords πŸ”

4.1. Definition πŸ’–

this document says a password is a string of Unicode code points [Unicode] that conforms to the OpaqueString profile (specified below) of the PRECIS FreeformClass defined in Section 4.3 of [RFC8264], and it's expressed in a standard Unicode Encoding Form (such as UTF-8 [RFC3629]) 🌸

the syntax for a password is defined using the Augmented Backus-Naur Form (ABNF) [RFC5234] πŸ“œ

password   = 1*(freepoint)
             ;
             ; a "freepoint" is a Unicode code point that
             ; can be contained in a string conforming to
             ; the PRECIS FreeformClass
             ;

everything that isn't explicitly allowed in the PRECIS FreeformClass is disallowed 🚧. that includes private-use code points, surrogate code points, and the other code points and blocks listed as "Prohibited Output" in Section 2.3 of [RFC4013] (when corrected per [Err1812]) πŸ™ˆ

a password MUST NOT be zero bytes in length. this rule gets enforced after any normalization and mapping of code points 🫢

Note: Some existing systems let an empty string sit where a password would go (for example, command-line tools that might get called from an automated script, or servers that might need to restart without a human around). From the perspective of this document (and RFC 4013 before it), these empty strings are NOT passwords. They're just workarounds for the practical difficulty of using passwords in certain scenarios πŸ§ƒ
Note: The zero-length password ban is NOT a recommendation about password strength (a one-byte password is super insecure, obviously 😭). It's there to stop apps from accidentally leaving the password out entirely. That can happen with internationalized strings, because a non-empty sequence of characters can turn into a zero-length password after canonicalization πŸ’€

in protocols that hand passwords to a cryptographic algorithm like a hash function, the client will need to perform enforcement of the OpaqueString profile rules before applying the algorithm. that's because the server never gets to see the password in plaintext form πŸ”₯

4.2. OpaqueString Profile 🫧

the OpaqueString profile is defined in the sections that follow, including detailed info about preparation, enforcement, and comparison. (if you want the difference between those actions spelled out, check [RFC8264] πŸ“š)

4.2.1. Preparation 🌟

an entity that prepares a string under this profile MUST ensure the string consists only of Unicode code points that are explicitly allowed by the FreeformClass string class defined in [RFC8264] πŸ’…

4.2.2. Enforcement

An entity that enforces this profile MUST prepare a string as described in Section 4.2.1 and MUST also apply the rules specified below for the OpaqueString profile (these rules MUST be applied in the order shown):

  1. Width Mapping Rule: Fullwidth and halfwidth code points MUST NOT be mapped to their decomposition mappings (see Unicode Standard Annex #11 [UAX11]).
  2. Additional Mapping Rule: Any instances of non-ASCII space MUST be mapped to SPACE (U+0020); a non-ASCII space is any Unicode code point having a Unicode general category of "Zs", with the exception of SPACE (U+0020). As was the case in RFC 4013, the inclusion of only SPACE (U+0020) prevents confusion with various non-ASCII space code points, many of which are difficult to reproduce across different input methods.
  3. Case Mapping Rule: There is no case mapping rule (because mapping uppercase and titlecase code points to their lowercase equivalents would lead to false accepts and thus to reduced security).
  4. Normalization Rule: Unicode Normalization Form C (NFC) MUST be applied to all strings.
  5. Directionality Rule: There is no directionality rule. The "Bidi Rule" (defined in [RFC5893]) and similar rules are unnecessary and inapplicable to passwords, because they can reduce the repertoire of characters that are allowed in a string and therefore reduce the amount of entropy that is possible in a password. Such rules are intended to minimize the possibility that the same string will be displayed differently on a layout system set for right-to-left display and a layout system set for left-to-right display; however, passwords are typically not displayed at all and are rarely meant to be interoperable across different layout systems in the way that non-secret strings like domain names and usernames are. Furthermore, it is perfectly acceptable for opaque strings other than passwords to be presented differently in different layout systems, as long as the presentation is consistent in any given layout system.

The result of the foregoing operations is an output string that conforms to the OpaqueString profile. Until an implementation produces such an output string, it MUST NOT treat the string as conforming (in particular, it MUST NOT assume that an input string is conforming before the enforcement operation has been completed).

4.2.3. Comparison

An entity that performs comparison of two strings according to this profile MUST prepare each string as specified in Section 4.2.1 and then MUST enforce the rules specified in Section 4.2.2. The two strings are to be considered equivalent if and only if they are an exact octet-for-octet match (sometimes called "bit-string identity").

Until an implementation determines whether two strings are to be considered equivalent, it MUST NOT treat them as equivalent (in particular, it MUST NOT assume that two input strings are equivalent before the comparison operation has been completed).

See Section 8.2 regarding comparison of passwords and passphrases.

4.3. Examples

The following examples illustrate a small number of passwords that are consistent with the format defined above (note that the characters "<" and ">" are used here to delineate the actual passwords and are not part of the password strings).

+------------------------------------+------------------------------+
| # | Password                       | Notes                        |
+------------------------------------+------------------------------+
| 12| <correct horse battery staple> | SPACE (U+0020) is allowed    |
+------------------------------------+------------------------------+
| 13| <Correct Horse Battery Staple> | Differs by case from         |
|   |                                | example 12                   |
+------------------------------------+------------------------------+
| 14| <Ο€ΓŸΓ₯>                          | Non-ASCII letters are OK     |
|   |                                | (e.g., GREEK SMALL LETTER    |
|   |                                | PI (U+03C0))                 |
+------------------------------------+------------------------------+
| 15| <Jack of ♦s>                   | Symbols are OK (e.g., BLACK  |
|   |                                | DIAMOND SUIT (U+2666))       |
+------------------------------------+------------------------------+
| 16| <foo bar>                      | OGHAM SPACE MARK (U+1680) is |
|   |                                | mapped to SPACE (U+0020);    |
|   |                                | thus, the full string is     |
|   |                                | mapped to <foo bar>          |
+------------------------------------+------------------------------+

                 Table 3: A Sample of Legal Passwords

The following examples illustrate strings that are not valid passwords because they violate the format defined above.

+------------------------------------+------------------------------+
| # | Password                       | Notes                        |
+------------------------------------+------------------------------+
| 17| <>                             | Zero-length passwords are    |
|   |                                | disallowed                   |
+------------------------------------+------------------------------+
| 18| <my cat is a &#x9;by>          | Control characters like TAB  |
|   |                                | (U+0009) are disallowed      |
+------------------------------------+------------------------------+

     Table 4: A Sample of Strings That Violate the Password Rules

Note: Following the "XML Notation" used in [RFC3987], the character TAB (U+0009) in example 18 is represented as &#x9 because otherwise it could not be shown in running text.

5. Use in Application Protocols ✨

This specification defines only the PRECIS-based rules for the handling of strings conforming to the UsernameCaseMapped and UsernameCasePreserved profiles of the PRECIS IdentifierClass, and strings conforming to the OpaqueString profile of the PRECIS FreeformClass. It is the responsibility of an application protocol to specify the protocol slots in which such strings can appear, the entities that are expected to enforce the rules governing such strings, and at what points during protocol processing or interface handling the rules need to be enforced. See Section 6 of [RFC8264] for guidelines on using PRECIS profiles in applications.

Above and beyond the PRECIS-based rules specified here, application protocols can also define application-specific rules governing such strings (rules regarding minimum or maximum length, further restrictions on allowable code points or character ranges, safeguards to mitigate the effects of visually similar characters, etc.), application-layer constructs (see Section 3.5), and related matters.

Some PRECIS profile definitions encourage entities that enforce the rules to be liberal in what they accept. However, for usernames and passwords such a policy can be problematic, because it can lead to false accepts. An in-depth discussion can be found in [RFC6943].

Applying the rules for any given PRECIS profile is not necessarily an idempotent procedure for all code points. Therefore, an implementation SHOULD apply the rules repeatedly until the output string is stable; if the output string does not stabilize after reapplying the rules three (3) additional times after the first application, the implementation SHOULD terminate application of the rules and reject the input string as invalid.

6. Migration 🧳

The rules defined in this specification differ slightly from those defined by the SASLprep specification [RFC4013] (but not from [RFC7613]). In order to smooth the process of migrating from SASLprep to the approach defined herein, the following sections describe these differences, along with their implications for migration, in more detail.

6.1. Usernames 🧹

okay so if your deployment has been using SASLprep for usernames, you might need to scrub existing data when you migrate to the rules in this spec. here's the tea πŸ«–πŸ’…

  • Normalization form (NFKC vs NFC) πŸ”₯ SASLprep specified Unicode Normalization Form KC (NFKC), but the UsernameCaseMapped and UsernameCasePreserved profiles use Unicode Normalization Form C (NFC). ngl this change is unlikely to cause significant problems, because NFKC maps code points with compatibility equivalents to those equivalents, whereas the PRECIS IdentifierClass entirely disallows Unicode code points with compatibility equivalents. so during comparison, NFKC is more "aggressive" about finding matches than NFC πŸ‘€ a few examples will give you the vibe:
    1. ΕΏ (LATIN SMALL LETTER LONG S, U+017F) is compatibility equivalent to s (LATIN SMALL LETTER S, U+0073).
    2. β…£ (ROMAN NUMERAL FOUR, U+2163) is compatibility equivalent to I (LATIN CAPITAL LETTER I, U+0049) and V (LATIN CAPITAL LETTER V, U+0056).
    3. fi (LATIN SMALL LIGATURE FI, U+FB01) is compatibility equivalent to f (LATIN SMALL LETTER F, U+0066) and i (LATIN SMALL LETTER I, U+0069).

Under SASLprep, the use of NFKC also handled the mapping of fullwidth and halfwidth code points to their decomposition mappings.

For migration purposes, operators might want to search their database of usernames for names containing Unicode code points with compatibility equivalents and, where there is no conflict, map those code points to their equivalents. Naturally, it is possible that during this process the operator will discover conflicting usernames. for instance, "HENRYIV" with the last two code points being LATIN CAPITAL LETTER I (U+0049) and LATIN CAPITAL LETTER V (U+0056) as opposed to "HENRYβ…£" with the last character being "β…£" (ROMAN NUMERAL FOUR, U+2163), which is compatibility equivalent to U+0049 and U+0056). in these cases, the operator will need to determine how to proceed, for instance, by disabling the account whose name contains a Unicode code point with a compatibility equivalent. such cases are probably rare, but it is important for operators to be aware of them πŸ₯Ί

  • "Characters commonly mapped to nothing" 🫧 SASLprep mapped the "characters commonly mapped to nothing" (from Appendix B.1 of [RFC3454]) to nothing, whereas the PRECIS IdentifierClass entirely disallows most of these code points. those correspond to the code points from the PRECIS "M" category defined under Section 9.13 of [RFC8264]. for migration purposes, the operator might want to remove from usernames any code points contained in the PRECIS "M" category (e.g., SOFT HYPHEN (U+00AD)). because these code points would have been "mapped to nothing" in Stringprep, in practice a user would not notice the difference if, upon migration to PRECIS, the code points are removed ✨
  • Case handling πŸ”€ SASLprep allowed uppercase and titlecase code points, whereas the UsernameCaseMapped profile maps uppercase and titlecase code points to their lowercase equivalents. (by contrast, the UsernameCasePreserved profile matches SASLprep in this regard.) for migration purposes, the operator can use either the UsernameCaseMapped profile (thus losing the case information) or the UsernameCasePreserved profile (thus ignoring case difference when comparing usernames). pick your fighter πŸ₯Š

6.2. Passwords πŸ”

depending on local service policy, migrating from SASLprep to this specification might not involve any scrubbing of data (because passwords might not be stored in the clear anyway). however, service providers need to be aware of possible issues that might arise during migration. the main ones:

  • Normalization form (NFKC vs NFC) πŸ’– SASLprep specified Unicode Normalization Form KC (NFKC), whereas the OpaqueString profile employs Unicode Normalization Form C (NFC). because NFKC is more aggressive about finding matches than NFC, in practice this change is unlikely to cause significant problems. it also has the security benefit of probably resulting in fewer false accepts when comparing passwords πŸ™Œ a few examples:
    1. ΕΏ (LATIN SMALL LETTER LONG S, U+017F) is compatibility equivalent to s (LATIN SMALL LETTER S, U+0073).
    2. β…£ (ROMAN NUMERAL FOUR, U+2163) is compatibility equivalent to I (LATIN CAPITAL LETTER I, U+0049) and V (LATIN CAPITAL LETTER V, U+0056).
    3. fi (LATIN SMALL LIGATURE FI, U+FB01) is compatibility equivalent to f (LATIN SMALL LETTER F, U+0066) and i (LATIN SMALL LETTER I, U+0069).

Under SASLprep, the use of NFKC also handled the mapping of fullwidth and halfwidth code points to their decomposition mappings. although it is expected that code points with compatibility equivalents are rare in existing passwords, some passwords that matched when SASLprep was used might no longer work when the rules in this specification are applied. yikes 😭

  • "Characters commonly mapped to nothing" 🫧 SASLprep mapped the "characters commonly mapped to nothing" (from Appendix B.1 of [RFC3454]) to nothing, whereas the PRECIS FreeformClass entirely disallows such code points. those correspond to the code points from the PRECIS "M" category defined under Section 9.13 of [RFC8264]. in practice, this change will probably have no effect on comparison, but user-oriented software might reject such code points instead of ignoring them during password preparation. so if a password field suddenly starts complaining, that's why πŸ™ˆ

7. IANA Considerations πŸ¦‹

IANA has made the updates described below.

7.1. UsernameCaseMapped Profile 🌸

IANA has added the following entry to the "PRECIS Profiles" registry.

Name:  UsernameCaseMapped.

Base Class:  IdentifierClass.

Applicability:  Usernames in security and application protocols.

Replaces:  The SASLprep profile of Stringprep.

Width Mapping Rule:  Map fullwidth and halfwidth code points to their
   decomposition mappings.

Additional Mapping Rule:  None.

Case Mapping Rule:  Map uppercase and titlecase code points to
   lowercase.

Normalization Rule:  NFC.

Directionality Rule:  The "Bidi Rule" defined in RFC 5893 applies.

Enforcement:  To be defined by security or application protocols that
   use this profile.

Specification:  Section 3.3 of RFC 8265.

7.2. UsernameCasePreserved Profile 🌷

IANA has added the following entry to the "PRECIS Profiles" registry.

Name:  UsernameCasePreserved.

Base Class:  IdentifierClass.

Applicability:  Usernames in security and application protocols.

Replaces:  The SASLprep profile of Stringprep.

Width Mapping Rule:  Map fullwidth and halfwidth code points to their
   decomposition mappings.

Additional Mapping Rule:  None.

Case Mapping Rule:  None.

Normalization Rule:  NFC.

Directionality Rule:  The "Bidi Rule" defined in RFC 5893 applies.

Enforcement:  To be defined by security or application protocols that
   use this profile.

Specification:  Section 3.4 of RFC 8265.

7.3. OpaqueString Profile 🧁

IANA has added the following entry to the "PRECIS Profiles" registry.

Name:  OpaqueString.

Base Class:  FreeformClass.

Applicability:  Passwords and other opaque strings in security and
   application protocols.

Replaces:  The SASLprep profile of Stringprep.

Width Mapping Rule:  None.

Additional Mapping Rule:  Map non-ASCII space code points to SPACE
   (U+0020).

Case Mapping Rule:  None.

Normalization Rule:  NFC.

Directionality Rule:  None.

Enforcement:  To be defined by security or application protocols that
   use this profile.

Specification:  Section 4.2 of RFC 8265.

7.4. Stringprep Profile 🧾

The Stringprep specification [RFC3454] did not provide for entries in the "Stringprep Profiles" registry to have any state except "Current" or "Not Current". because RFC 7613 obsoleted RFC 4013, which registered the SASLprep profile of Stringprep, IANA previously marked that profile as "Not Current" and cited RFC 7613 as an additional reference. IANA has modified the profile so that the current document is now cited as the additional reference πŸ’…


8. Security Considerations πŸ’€

8.1. Password/Passphrase Strength πŸ’ͺ

The ability to include a wide range of characters in passwords and passphrases can increase the potential for creating a strong password with high entropy. however, in practice, the ability to include such characters ought to be weighed against the possible need to reproduce them on various devices using various input methods. so yes, more characters are great, but your users still have to be able to type them πŸ“±βŒ¨οΈ

8.2. Password/Passphrase Comparison πŸ”

In systems that conform to modern best practices for security, verification of passwords during authentication will not use the comparison defined in Section 4.2.3. instead, because the system performs cryptographic calculations to verify the password, it will prepare the password as defined in Section 4.2.1 and enforce the rules as defined in Section 4.2.2 before performing the relevant calculations. the vibe is: compare the hashes, not the raw strings 🧐

8.3. Identifier Comparison πŸͺͺ

The process of comparing identifiers (such as SASL simple usernames, authentication identifiers, and authorization identifiers) can lead to either false rejects or false accepts, and both of these have security implications 🚨. a more detailed discussion can be found in [RFC6943].

8.4. Reuse of PRECIS πŸ”

The security considerations described in [RFC8264] apply to the IdentifierClass and FreeformClass string classes used in this document for usernames and passwords, respectively.

8.5. Reuse of Unicode 🌍

The security considerations described in [UTS39] apply to the use of Unicode code points in usernames and passwords.


9. References πŸ“š

9.1. Normative References πŸ“šβœ¨

Okay bestie, these are the must-read docs the spec leans on 🫢 Every entry is listed with its full details:

9.2. Informative References πŸ¦‹

These ones are the extra reading for when you want the full backstory πŸ’…

Appendix A. Changes from RFC 7613 πŸŽ€

Here's the glow-up tea β˜• These are all the changes made from [RFC7613]:

  • Corrected the order of operations for the UsernameCaseMapped profile to ensure consistency with [RFC8264]. πŸ’–
  • In accordance with working group discussions and updates to [RFC8264], removed the use of the Unicode toCaseFold() operation in favor of the Unicode toLowerCase() operation. 🧚
  • Modified the presentation (but not the content) of the rules. ✨
  • Removed UTF-8 as a mandatory encoding, because that is a matter for the application. πŸ“
  • Clarified several editorial matters. πŸ’…
  • Updated references. πŸ“š

See [RFC7613] for a description of the differences from [RFC4013]. It's giving history lesson πŸ™ˆ

Acknowledgements 🫢

Huge thanks to Christian Schudt and Sam Whited for their bug reports and feedback. You two are literally the reason this got better πŸ’œ

See [RFC7613] for acknowledgements related to the specification that this document supersedes. πŸ‘‘

Authors' Addresses πŸ¦‹

Here are the girlies who wrote it πŸ’–

Peter Saint-Andre
Jabber.org
P.O. Box 787
Parker, CO  80134
United States of America

Phone: +1 720 256 6756
Email: stpeter@jabber.org
URI:   https://www.jabber.org/
Alexey Melnikov
Isode Ltd
5 Castle Business Village
36 Station Road
Hampton, Middlesex  TW12 2BX
United Kingdom

Email: Alexey.Melnikov@isode.com
πŸ“¦ where this page comes from