From c727f120ff50f624a1ee3abe700d995c18314a0b Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Tue, 18 Apr 2017 14:50:50 +0300 Subject: [PATCH] Rename "scram" to "scram-sha-256" in pg_hba.conf and password_encryption. Per discussion, plain "scram" is confusing because we actually implement SCRAM-SHA-256 rather than the original SCRAM that uses SHA-1 as the hash algorithm. If we add support for SCRAM-SHA-512 or some other mechanism in the SCRAM family in the future, that would become even more confusing. Most of the internal files and functions still use just "scram" as a shorthand for SCRMA-SHA-256, but I did change PASSWORD_TYPE_SCRAM to PASSWORD_TYPE_SCRAM_SHA_256, as that could potentially be used by 3rd party extensions that hook into the password-check hook. Michael Paquier did this in an earlier version of the SCRAM patch set already, but I didn't include that in the version that was committed. Discussion: https://www.postgresql.org/message-id/fde71ff1-5858-90c8-99a9-1c2427e7bafb@iki.fi --- doc/src/sgml/client-auth.sgml | 15 ++++++++------- doc/src/sgml/config.sgml | 4 ++-- src/backend/commands/user.c | 8 ++++---- src/backend/libpq/auth-scram.c | 2 +- src/backend/libpq/auth.c | 16 ++++++++-------- src/backend/libpq/crypt.c | 10 +++++----- src/backend/libpq/hba.c | 4 ++-- src/backend/libpq/pg_hba.conf.sample | 8 ++++---- src/backend/utils/misc/guc.c | 2 +- src/bin/initdb/initdb.c | 16 ++++++++-------- src/include/libpq/crypt.h | 2 +- src/test/authentication/t/001_password.pl | 14 +++++++------- src/test/authentication/t/002_saslprep.pl | 4 ++-- src/test/regress/expected/password.out | 8 ++++---- src/test/regress/sql/password.sql | 6 +++--- 15 files changed, 60 insertions(+), 59 deletions(-) diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml index d871c041ce..819db811b2 100644 --- a/doc/src/sgml/client-auth.sgml +++ b/doc/src/sgml/client-auth.sgml @@ -412,7 +412,7 @@ hostnossl database user - scram + scram-sha-256 Perform SCRAM-SHA-256 authentication to verify the user's @@ -683,7 +683,7 @@ host postgres all 192.168.93.0/24 ident # "postgres" if the user's password is correctly supplied. # # TYPE DATABASE USER ADDRESS METHOD -host postgres all 192.168.12.10/32 scram +host postgres all 192.168.12.10/32 scram-sha-256 # Allow any user from hosts in the example.com domain to connect to # any database if the user's password is correctly supplied. @@ -694,7 +694,7 @@ host postgres all 192.168.12.10/32 scram # # TYPE DATABASE USER ADDRESS METHOD host all mike .example.com md5 -host all all .example.com scram +host all all .example.com scram-sha-256 # In the absence of preceding "host" lines, these two lines will # reject all connections from 192.168.54.1 (since that entry will be @@ -922,7 +922,7 @@ omicron bryanh guest1 - The password-based authentication methods are scram, + The password-based authentication methods are scram-sha-256, md5, and password. These methods operate similarly except for the way that the password is sent across the connection. @@ -939,8 +939,9 @@ omicron bryanh guest1 - scram performs SCRAM-SHA-256 authentication, as described - in RFC5802. It + scram-sha-256 performs SCRAM-SHA-256 authentication, as + described in + RFC5802. It is a challenge-response scheme, that prevents password sniffing on untrusted connections. It is more secure than the md5 method, but might not be supported by older clients. @@ -953,7 +954,7 @@ omicron bryanh guest1 protection if an attacker manages to steal the password hash from the server, and it cannot be used with the feature. For all other users, - md5 works the same as scram. + md5 works the same as scram-sha-256. diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 744c5e8f37..e02b0c80df 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -1194,8 +1194,8 @@ include_dir 'conf.d' stores the password as an MD5 hash. Setting this to plain stores it in plaintext. on and off are also accepted, as aliases for md5 and plain, respectively. Setting - this parameter to scram will encrypt the password with - SCRAM-SHA-256. + this parameter to scram-sha-256 will encrypt the password + with SCRAM-SHA-256. diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index de264974ae..c719682274 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -140,8 +140,8 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt) dpassword = defel; if (strcmp(defel->defname, "encryptedPassword") == 0) { - if (Password_encryption == PASSWORD_TYPE_SCRAM) - password_type = PASSWORD_TYPE_SCRAM; + if (Password_encryption == PASSWORD_TYPE_SCRAM_SHA_256) + password_type = PASSWORD_TYPE_SCRAM_SHA_256; else password_type = PASSWORD_TYPE_MD5; } @@ -548,8 +548,8 @@ AlterRole(AlterRoleStmt *stmt) dpassword = defel; if (strcmp(defel->defname, "encryptedPassword") == 0) { - if (Password_encryption == PASSWORD_TYPE_SCRAM) - password_type = PASSWORD_TYPE_SCRAM; + if (Password_encryption == PASSWORD_TYPE_SCRAM_SHA_256) + password_type = PASSWORD_TYPE_SCRAM_SHA_256; else password_type = PASSWORD_TYPE_MD5; } diff --git a/src/backend/libpq/auth-scram.c b/src/backend/libpq/auth-scram.c index 338afede9d..76c502d415 100644 --- a/src/backend/libpq/auth-scram.c +++ b/src/backend/libpq/auth-scram.c @@ -183,7 +183,7 @@ pg_be_scram_init(const char *username, const char *shadow_pass) { int password_type = get_password_type(shadow_pass); - if (password_type == PASSWORD_TYPE_SCRAM) + if (password_type == PASSWORD_TYPE_SCRAM_SHA_256) { if (parse_scram_verifier(shadow_pass, &state->salt, &state->iterations, state->StoredKey, state->ServerKey)) diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 848561e188..ab4be21943 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -50,7 +50,7 @@ static char *recv_password_packet(Port *port); /*---------------------------------------------------------------- - * Password-based authentication methods (password, md5, and scram) + * Password-based authentication methods (password, md5, and scram-sha-256) *---------------------------------------------------------------- */ static int CheckPasswordAuth(Port *port, char **logdetail); @@ -757,10 +757,10 @@ CheckPWChallengeAuth(Port *port, char **logdetail) * If the user does not exist, or has no password, we still go through the * motions of authentication, to avoid revealing to the client that the * user didn't exist. If 'md5' is allowed, we choose whether to use 'md5' - * or 'scram' authentication based on current password_encryption setting. - * The idea is that most genuine users probably have a password of that - * type, if we pretend that this user had a password of that type, too, it - * "blends in" best. + * or 'scram-sha-256' authentication based on current password_encryption + * setting. The idea is that most genuine users probably have a password + * of that type, if we pretend that this user had a password of that type, + * too, it "blends in" best. * * If the user had a password, but it was expired, we'll use the details * of the expired password for the authentication, but report it as @@ -773,9 +773,9 @@ CheckPWChallengeAuth(Port *port, char **logdetail) /* * If 'md5' authentication is allowed, decide whether to perform 'md5' or - * 'scram' authentication based on the type of password the user has. If - * it's an MD5 hash, we must do MD5 authentication, and if it's a SCRAM - * verifier, we must do SCRAM authentication. If it's stored in + * 'scram-sha-256' authentication based on the type of password the user + * has. If it's an MD5 hash, we must do MD5 authentication, and if it's + * a SCRAM verifier, we must do SCRAM authentication. If it's stored in * plaintext, we could do either one, so we opt for the more secure * mechanism, SCRAM. * diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c index 34beab5334..03ef3cc652 100644 --- a/src/backend/libpq/crypt.c +++ b/src/backend/libpq/crypt.c @@ -101,7 +101,7 @@ get_password_type(const char *shadow_pass) if (strncmp(shadow_pass, "md5", 3) == 0 && strlen(shadow_pass) == MD5_PASSWD_LEN) return PASSWORD_TYPE_MD5; if (strncmp(shadow_pass, "scram-sha-256:", strlen("scram-sha-256:")) == 0) - return PASSWORD_TYPE_SCRAM; + return PASSWORD_TYPE_SCRAM_SHA_256; return PASSWORD_TYPE_PLAINTEXT; } @@ -141,7 +141,7 @@ encrypt_password(PasswordType target_type, const char *role, elog(ERROR, "password encryption failed"); return encrypted_password; - case PASSWORD_TYPE_SCRAM: + case PASSWORD_TYPE_SCRAM_SHA_256: /* * cannot convert a SCRAM verifier to an MD5 hash, so fall @@ -152,7 +152,7 @@ encrypt_password(PasswordType target_type, const char *role, } break; - case PASSWORD_TYPE_SCRAM: + case PASSWORD_TYPE_SCRAM_SHA_256: switch (guessed_type) { case PASSWORD_TYPE_PLAINTEXT: @@ -164,7 +164,7 @@ encrypt_password(PasswordType target_type, const char *role, * cannot convert an MD5 hash to a SCRAM verifier, so fall * through to save the MD5 hash instead. */ - case PASSWORD_TYPE_SCRAM: + case PASSWORD_TYPE_SCRAM_SHA_256: return pstrdup(password); } break; @@ -280,7 +280,7 @@ plain_crypt_verify(const char *role, const char *shadow_pass, */ switch (get_password_type(shadow_pass)) { - case PASSWORD_TYPE_SCRAM: + case PASSWORD_TYPE_SCRAM_SHA_256: if (scram_verify_plain_password(role, client_pass, shadow_pass)) diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c index af89fe898a..5561c399da 100644 --- a/src/backend/libpq/hba.c +++ b/src/backend/libpq/hba.c @@ -126,7 +126,7 @@ static const char *const UserAuthName[] = "ident", "password", "md5", - "scram", + "scram-sha256", "gss", "sspi", "pam", @@ -1327,7 +1327,7 @@ parse_hba_line(TokenizedLine *tok_line, int elevel) } parsedline->auth_method = uaMD5; } - else if (strcmp(token->string, "scram") == 0) + else if (strcmp(token->string, "scram-sha-256") == 0) parsedline->auth_method = uaSCRAM; else if (strcmp(token->string, "pam") == 0) #ifdef USE_PAM diff --git a/src/backend/libpq/pg_hba.conf.sample b/src/backend/libpq/pg_hba.conf.sample index 6b1778a721..c853e36232 100644 --- a/src/backend/libpq/pg_hba.conf.sample +++ b/src/backend/libpq/pg_hba.conf.sample @@ -42,10 +42,10 @@ # or "samenet" to match any address in any subnet that the server is # directly connected to. # -# METHOD can be "trust", "reject", "md5", "password", "scram", "gss", -# "sspi", "ident", "peer", "pam", "ldap", "radius" or "cert". Note that -# "password" sends passwords in clear text; "md5" or "scram" are preferred -# since they send encrypted passwords. +# METHOD can be "trust", "reject", "md5", "password", "scram-sha-256", +# "gss", "sspi", "ident", "peer", "pam", "ldap", "radius" or "cert". +# Note that "password" sends passwords in clear text; "md5" or +# "scram-sha-256" are preferred since they send encrypted passwords. # # OPTIONS are a set of options for the authentication in the format # NAME=VALUE. The available options depend on the different diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 9ad8361a9b..a414fb2c76 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -410,7 +410,7 @@ static const struct config_enum_entry force_parallel_mode_options[] = { static const struct config_enum_entry password_encryption_options[] = { {"plain", PASSWORD_TYPE_PLAINTEXT, false}, {"md5", PASSWORD_TYPE_MD5, false}, - {"scram", PASSWORD_TYPE_SCRAM, false}, + {"scram-sha-256", PASSWORD_TYPE_SCRAM_SHA_256, false}, {"off", PASSWORD_TYPE_PLAINTEXT, false}, {"on", PASSWORD_TYPE_MD5, false}, {"true", PASSWORD_TYPE_MD5, true}, diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index d40ed412fc..95da8b7722 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -77,7 +77,7 @@ extern const char *select_default_timezone(const char *share_path); static const char *const auth_methods_host[] = { - "trust", "reject", "md5", "password", "scram", "ident", "radius", + "trust", "reject", "scram-sha-256", "md5", "password", "ident", "radius", #ifdef ENABLE_GSS "gss", #endif @@ -99,7 +99,7 @@ static const char *const auth_methods_host[] = { NULL }; static const char *const auth_methods_local[] = { - "trust", "reject", "md5", "scram", "password", "peer", "radius", + "trust", "reject", "scram-sha-256", "md5", "password", "peer", "radius", #ifdef USE_PAM "pam", "pam ", #endif @@ -1130,12 +1130,12 @@ setup_config(void) "#update_process_title = off"); #endif - if (strcmp(authmethodlocal, "scram") == 0 || - strcmp(authmethodhost, "scram") == 0) + if (strcmp(authmethodlocal, "scram-sha-256") == 0 || + strcmp(authmethodhost, "scram-sha-256") == 0) { conflines = replace_token(conflines, "#password_encryption = md5", - "password_encryption = scram"); + "password_encryption = scram-sha-256"); } snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data); @@ -2329,16 +2329,16 @@ check_need_password(const char *authmethodlocal, const char *authmethodhost) { if ((strcmp(authmethodlocal, "md5") == 0 || strcmp(authmethodlocal, "password") == 0 || - strcmp(authmethodlocal, "scram") == 0) && + strcmp(authmethodlocal, "scram-sha-256") == 0) && (strcmp(authmethodhost, "md5") == 0 || strcmp(authmethodhost, "password") == 0 || - strcmp(authmethodhost, "scram") == 0) && + strcmp(authmethodhost, "scram-sha-256") == 0) && !(pwprompt || pwfilename)) { fprintf(stderr, _("%s: must specify a password for the superuser to enable %s authentication\n"), progname, (strcmp(authmethodlocal, "md5") == 0 || strcmp(authmethodlocal, "password") == 0 || - strcmp(authmethodlocal, "scram") == 0) + strcmp(authmethodlocal, "scram-sha-256") == 0) ? authmethodlocal : authmethodhost); exit(1); diff --git a/src/include/libpq/crypt.h b/src/include/libpq/crypt.h index 3b5da69b08..63724f39ee 100644 --- a/src/include/libpq/crypt.h +++ b/src/include/libpq/crypt.h @@ -25,7 +25,7 @@ typedef enum PasswordType { PASSWORD_TYPE_PLAINTEXT = 0, PASSWORD_TYPE_MD5, - PASSWORD_TYPE_SCRAM + PASSWORD_TYPE_SCRAM_SHA_256 } PasswordType; extern PasswordType get_password_type(const char *shadow_pass); diff --git a/src/test/authentication/t/001_password.pl b/src/test/authentication/t/001_password.pl index d7bc13bd58..216bdc031c 100644 --- a/src/test/authentication/t/001_password.pl +++ b/src/test/authentication/t/001_password.pl @@ -51,7 +51,7 @@ SKIP: # Create 3 roles with different password methods for each one. The same # password is used for all of them. - $node->safe_psql('postgres', "SET password_encryption='scram'; CREATE ROLE scram_role LOGIN PASSWORD 'pass';"); + $node->safe_psql('postgres', "SET password_encryption='scram-sha-256'; CREATE ROLE scram_role LOGIN PASSWORD 'pass';"); $node->safe_psql('postgres', "SET password_encryption='md5'; CREATE ROLE md5_role LOGIN PASSWORD 'pass';"); $node->safe_psql('postgres', "SET password_encryption='plain'; CREATE ROLE plain_role LOGIN PASSWORD 'pass';"); $ENV{"PGPASSWORD"} = 'pass'; @@ -68,12 +68,12 @@ SKIP: test_role($node, 'md5_role', 'password', 0); test_role($node, 'plain_role', 'password', 0); - # For "scram" method, user "plain_role" and "scram_role" should be able to - # connect. - reset_pg_hba($node, 'scram'); - test_role($node, 'scram_role', 'scram', 0); - test_role($node, 'md5_role', 'scram', 2); - test_role($node, 'plain_role', 'scram', 0); + # For "scram-sha-256" method, user "plain_role" and "scram_role" should + # be able to connect. + reset_pg_hba($node, 'scram-sha-256'); + test_role($node, 'scram_role', 'scram-sha-256', 0); + test_role($node, 'md5_role', 'scram-sha-256', 2); + test_role($node, 'plain_role', 'scram-sha-256', 0); # For "md5" method, all users should be able to connect (SCRAM # authentication will be performed for the user with a scram verifier.) diff --git a/src/test/authentication/t/002_saslprep.pl b/src/test/authentication/t/002_saslprep.pl index 7e373ed7bf..67ba92cdd9 100644 --- a/src/test/authentication/t/002_saslprep.pl +++ b/src/test/authentication/t/002_saslprep.pl @@ -63,7 +63,7 @@ SKIP: # Create test roles. $node->safe_psql('postgres', -"SET password_encryption='scram'; +"SET password_encryption='scram-sha-256'; SET client_encoding='utf8'; CREATE ROLE saslpreptest1_role LOGIN PASSWORD 'IX'; CREATE ROLE saslpreptest4a_role LOGIN PASSWORD 'a'; @@ -73,7 +73,7 @@ SKIP: "); # Require password from now on. - reset_pg_hba($node, 'scram'); + reset_pg_hba($node, 'scram-sha-256'); # Check that #1 and #5 are treated the same as just 'IX' test_login($node, 'saslpreptest1_role', "I\xc2\xadX", 0); diff --git a/src/test/regress/expected/password.out b/src/test/regress/expected/password.out index c503e43abe..676b3e6ff3 100644 --- a/src/test/regress/expected/password.out +++ b/src/test/regress/expected/password.out @@ -4,11 +4,11 @@ -- Tests for GUC password_encryption SET password_encryption = 'novalue'; -- error ERROR: invalid value for parameter "password_encryption": "novalue" -HINT: Available values: plain, md5, scram, off, on. +HINT: Available values: plain, md5, scram-sha-256, off, on. SET password_encryption = true; -- ok SET password_encryption = 'md5'; -- ok SET password_encryption = 'plain'; -- ok -SET password_encryption = 'scram'; -- ok +SET password_encryption = 'scram-sha-256'; -- ok -- consistency of password entries SET password_encryption = 'plain'; CREATE ROLE regress_passwd1 PASSWORD 'role_pwd1'; @@ -16,7 +16,7 @@ SET password_encryption = 'md5'; CREATE ROLE regress_passwd2 PASSWORD 'role_pwd2'; SET password_encryption = 'on'; CREATE ROLE regress_passwd3 PASSWORD 'role_pwd3'; -SET password_encryption = 'scram'; +SET password_encryption = 'scram-sha-256'; CREATE ROLE regress_passwd4 PASSWORD 'role_pwd4'; SET password_encryption = 'plain'; CREATE ROLE regress_passwd5 PASSWORD NULL; @@ -60,7 +60,7 @@ ALTER ROLE regress_passwd2 UNENCRYPTED PASSWORD 'md5dfa155cadd5f4ad57860162f3fab SET password_encryption = 'md5'; ALTER ROLE regress_passwd3 ENCRYPTED PASSWORD 'foo'; -- encrypted with MD5 ALTER ROLE regress_passwd4 ENCRYPTED PASSWORD 'scram-sha-256:VLK4RMaQLCvNtQ==:4096:3ded2376f7aafa93b1bdbd71bcc18b7d6ee50ed018029cc583d152ef3fc7d430:a6dd36dfc94c181956a6ae95f05e01b1864f0a22a2657d1de4ba84d2a24dc438'; -- client-supplied SCRAM verifier, use as it is -SET password_encryption = 'scram'; +SET password_encryption = 'scram-sha-256'; ALTER ROLE regress_passwd5 ENCRYPTED PASSWORD 'foo'; -- create SCRAM verifier CREATE ROLE regress_passwd6 ENCRYPTED PASSWORD 'md53725413363ab045e20521bf36b8d8d7f'; -- encrypted with MD5, use as it is SELECT rolname, regexp_replace(rolpassword, '(scram-sha-256):([a-zA-Z0-9+/]+==):(\d+):(\w+):(\w+)', '\1::\3::') as rolpassword_masked diff --git a/src/test/regress/sql/password.sql b/src/test/regress/sql/password.sql index f4b3a9ac3a..95557e4566 100644 --- a/src/test/regress/sql/password.sql +++ b/src/test/regress/sql/password.sql @@ -7,7 +7,7 @@ SET password_encryption = 'novalue'; -- error SET password_encryption = true; -- ok SET password_encryption = 'md5'; -- ok SET password_encryption = 'plain'; -- ok -SET password_encryption = 'scram'; -- ok +SET password_encryption = 'scram-sha-256'; -- ok -- consistency of password entries SET password_encryption = 'plain'; @@ -16,7 +16,7 @@ SET password_encryption = 'md5'; CREATE ROLE regress_passwd2 PASSWORD 'role_pwd2'; SET password_encryption = 'on'; CREATE ROLE regress_passwd3 PASSWORD 'role_pwd3'; -SET password_encryption = 'scram'; +SET password_encryption = 'scram-sha-256'; CREATE ROLE regress_passwd4 PASSWORD 'role_pwd4'; SET password_encryption = 'plain'; CREATE ROLE regress_passwd5 PASSWORD NULL; @@ -50,7 +50,7 @@ ALTER ROLE regress_passwd3 ENCRYPTED PASSWORD 'foo'; -- encrypted with MD5 ALTER ROLE regress_passwd4 ENCRYPTED PASSWORD 'scram-sha-256:VLK4RMaQLCvNtQ==:4096:3ded2376f7aafa93b1bdbd71bcc18b7d6ee50ed018029cc583d152ef3fc7d430:a6dd36dfc94c181956a6ae95f05e01b1864f0a22a2657d1de4ba84d2a24dc438'; -- client-supplied SCRAM verifier, use as it is -SET password_encryption = 'scram'; +SET password_encryption = 'scram-sha-256'; ALTER ROLE regress_passwd5 ENCRYPTED PASSWORD 'foo'; -- create SCRAM verifier CREATE ROLE regress_passwd6 ENCRYPTED PASSWORD 'md53725413363ab045e20521bf36b8d8d7f'; -- encrypted with MD5, use as it is