Return-Path: X-Original-To: apmail-couchdb-commits-archive@www.apache.org Delivered-To: apmail-couchdb-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 25E2611C51 for ; Tue, 15 Apr 2014 20:49:40 +0000 (UTC) Received: (qmail 69854 invoked by uid 500); 15 Apr 2014 20:49:02 -0000 Delivered-To: apmail-couchdb-commits-archive@couchdb.apache.org Received: (qmail 69730 invoked by uid 500); 15 Apr 2014 20:49:01 -0000 Mailing-List: contact commits-help@couchdb.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@couchdb.apache.org Delivered-To: mailing list commits@couchdb.apache.org Received: (qmail 69651 invoked by uid 99); 15 Apr 2014 20:48:59 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 15 Apr 2014 20:48:59 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id BCB4D93049B; Tue, 15 Apr 2014 20:48:58 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: deathbear@apache.org To: commits@couchdb.apache.org Date: Tue, 15 Apr 2014 20:49:02 -0000 Message-Id: In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [05/27] couchdb commit: updated refs/heads/Update-Sidebar-Ui to 73c8a06 Verify that auth-related properties are well-formed Passing unexpected values to auth fields can result in server issues. Notably, setting "iterations" to a string will cause an infinite loop as the comparison 'when Iteration > Iterations' will never evaluate to true. The latest validate_doc_update prevents user docs with this problem and administrators can deploy that check themselves (and only administrators can edit design documents). A server administrator can also insist on lower and upper bounds for iteration count to reject weakly protected passwords and resource-hungry passwords respectively. COUCHDB-2221 Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/dbe769c6 Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/dbe769c6 Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/dbe769c6 Branch: refs/heads/Update-Sidebar-Ui Commit: dbe769c604e5f1e000594336f8c4546bf9e3fd5a Parents: 9f6a919 Author: Robert Newson Authored: Sun Apr 6 18:31:15 2014 +0100 Committer: Robert Newson Committed: Sun Apr 6 22:09:54 2014 +0100 ---------------------------------------------------------------------- etc/couchdb/default.ini.tpl.in | 2 ++ share/doc/src/config/auth.rst | 24 ++++++++++++++++++++++++ src/couchdb/couch_httpd_auth.erl | 17 +++++++++++++++++ src/couchdb/couch_passwords.erl | 15 +++++++++++---- 4 files changed, 54 insertions(+), 4 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb/blob/dbe769c6/etc/couchdb/default.ini.tpl.in ---------------------------------------------------------------------- diff --git a/etc/couchdb/default.ini.tpl.in b/etc/couchdb/default.ini.tpl.in index a0dd7db..934c6cd 100644 --- a/etc/couchdb/default.ini.tpl.in +++ b/etc/couchdb/default.ini.tpl.in @@ -72,6 +72,8 @@ timeout = 600 ; number of seconds before automatic logout auth_cache_size = 50 ; size is number of cache entries allow_persistent_cookies = false ; set to true to allow persistent cookies iterations = 10 ; iterations for password hashing +; min_iterations = 1 +; max_iterations = 1000000000 ; comma-separated list of public fields, 404 if empty ; public_fields = http://git-wip-us.apache.org/repos/asf/couchdb/blob/dbe769c6/share/doc/src/config/auth.rst ---------------------------------------------------------------------- diff --git a/share/doc/src/config/auth.rst b/share/doc/src/config/auth.rst index 4127288..8311140 100644 --- a/share/doc/src/config/auth.rst +++ b/share/doc/src/config/auth.rst @@ -166,6 +166,30 @@ Authentication Configuration [couch_httpd_auth] iterations = 10000 + .. config:option:: min_iterations :: Minimum PBKDF2 iterations count + + .. versionadded:: 1.6 + + The minimum number of iterations allowed for passwords hashed by + the PBKDF2 algorithm. Any user with fewer iterations is forbidden. + + :: + + [couch_httpd_auth] + min_iterations = 100 + + .. config:option:: max_iterations :: Maximum PBKDF2 iterations count + + .. versionadded:: 1.6 + + The maximum number of iterations allowed for passwords hashed by + the PBKDF2 algorithm. Any user with greater iterations is forbidden. + + :: + + [couch_httpd_auth] + max_iterations = 100000 + .. config:option:: proxy_use_secret :: Force proxy auth use secret token http://git-wip-us.apache.org/repos/asf/couchdb/blob/dbe769c6/src/couchdb/couch_httpd_auth.erl ---------------------------------------------------------------------- diff --git a/src/couchdb/couch_httpd_auth.erl b/src/couchdb/couch_httpd_auth.erl index 08841fb..6888f06 100644 --- a/src/couchdb/couch_httpd_auth.erl +++ b/src/couchdb/couch_httpd_auth.erl @@ -368,11 +368,28 @@ authenticate(Pass, UserProps) -> couch_util:get_value(<<"password_sha">>, UserProps, nil)}; <<"pbkdf2">> -> Iterations = couch_util:get_value(<<"iterations">>, UserProps, 10000), + verify_iterations(Iterations), {couch_passwords:pbkdf2(Pass, UserSalt, Iterations), couch_util:get_value(<<"derived_key">>, UserProps, nil)} end, couch_passwords:verify(PasswordHash, ExpectedHash). +verify_iterations(Iterations) when is_integer(Iterations) -> + Min = list_to_integer(couch_config:get("couch_httpd_auth", "min_iterations", "1")), + Max = list_to_integer(couch_config:get("couch_httpd_auth", "max_iterations", "1000000000")), + case Iterations < Min of + true -> + throw({forbidden, <<"Iteration count is too low for this server">>}); + false -> + ok + end, + case Iterations > Max of + true -> + throw({forbidden, <<"Iteration count is too high for this server">>}); + false -> + ok + end. + auth_name(String) when is_list(String) -> [_,_,_,_,_,Name|_] = re:split(String, "[\\W_]", [{return, list}]), ?l2b(Name). http://git-wip-us.apache.org/repos/asf/couchdb/blob/dbe769c6/src/couchdb/couch_passwords.erl ---------------------------------------------------------------------- diff --git a/src/couchdb/couch_passwords.erl b/src/couchdb/couch_passwords.erl index d9e6836..bbf6d9a 100644 --- a/src/couchdb/couch_passwords.erl +++ b/src/couchdb/couch_passwords.erl @@ -22,12 +22,12 @@ %% legacy scheme, not used for new passwords. -spec simple(binary(), binary()) -> binary(). -simple(Password, Salt) -> +simple(Password, Salt) when is_binary(Password), is_binary(Salt) -> ?l2b(couch_util:to_hex(crypto:sha(<>))). %% CouchDB utility functions -spec hash_admin_password(binary()) -> binary(). -hash_admin_password(ClearPassword) -> +hash_admin_password(ClearPassword) when is_binary(ClearPassword) -> Iterations = couch_config:get("couch_httpd_auth", "iterations", "10000"), Salt = couch_uuids:random(), DerivedKey = couch_passwords:pbkdf2(couch_util:to_binary(ClearPassword), @@ -50,7 +50,10 @@ get_unhashed_admins() -> %% Current scheme, much stronger. -spec pbkdf2(binary(), binary(), integer()) -> binary(). -pbkdf2(Password, Salt, Iterations) -> +pbkdf2(Password, Salt, Iterations) when is_binary(Password), + is_binary(Salt), + is_integer(Iterations), + Iterations > 0 -> {ok, Result} = pbkdf2(Password, Salt, Iterations, ?SHA1_OUTPUT_LENGTH), Result. @@ -59,7 +62,11 @@ pbkdf2(Password, Salt, Iterations) -> pbkdf2(_Password, _Salt, _Iterations, DerivedLength) when DerivedLength > ?MAX_DERIVED_KEY_LENGTH -> {error, derived_key_too_long}; -pbkdf2(Password, Salt, Iterations, DerivedLength) -> +pbkdf2(Password, Salt, Iterations, DerivedLength) when is_binary(Password), + is_binary(Salt), + is_integer(Iterations), + Iterations > 0, + is_integer(DerivedLength) -> L = ceiling(DerivedLength / ?SHA1_OUTPUT_LENGTH), <> = iolist_to_binary(pbkdf2(Password, Salt, Iterations, L, 1, [])),