Fossil

Artifact [135405d9]
Login

Artifact [135405d9]

Artifact 135405d9e2261e759d0d85fd2104848589c485e6:


<title>Fossil Password Management</title>
<h1 align="center">Password Management</h1>

Fossil handles user authentication using passwords.
Passwords are unique to each repository.  Passwords are not part of the
persistent state of a project.  Passwords are not versioned and
are not transmitted from one repository to another during a sync.
Passwords are local configuration information that can (and usually does)
vary from one repository to the next within the same project.

Passwords are stored in the PW field of the USER table.
In older versions of Fossil (prior to
[/timeline?c=2010-01-10T20:56:30 | 2010-01-11]) the password
is stored as cleartext.  In newer versions of Fossil, the password
can be either cleartext or an SHA1 hash (written as a 40-character
lower-case hexadecimal number).  If the USER.PW field contains
a 40-character string, that string is assumed to be a SHA1 hash.
If the size of USER.PW is anything other than 40 characters, then
it is understood as a plain-text password.

The SHA1 hash in the USER.PW field is a hash of a string composed of
the project-code, the user login, and the user cleartext password.
Suppose user "alice" with password "asdfg" had an account on the
Fossil self-hosting repository.  Then the value of USER.PW
for alice would be the SHA1 hash of

<blockquote>
CE59BB9F186226D80E49D1FA2DB29F935CCA0333/alice/asdfg
</blockquote>

That hash value is "f1b699cc9af3eeb98e5de244ca7802ae38e77bae".  Note
that by including the project-code and the login as part of the hash,
a different USER.PW value results even if two or more users on the
repository select the same "asdfg" password or if user alice reuses the
same password on multiple projects.

Whenever a password is changed using the web interface or using the
"user" command-line method, the new password is stored using the SHA1
encoding.  Thus, cleartext passwords will gradually migrate to become
SHA1 passwords.  All remaining cleartext passwords can be converted to
SHA1 passwords using the following command:

<blockquote><pre>
fossil test-hash-passwords <i>REPOSITORY-NAME</i>
</pre></blockquote>

Remember that converting from cleartext to SHA1 passwords is an
irreversible operation.

The only way to insert a new cleartext password into the USER table
is to do so manually using SQL commands.  For example:

<blockquote><pre>
UPDATE user SET pw='asdfg' WHERE login='alice';
</pre></blockquote>

Note that an password that is an empty string or NULL will disable
all login for that user.   Thus, to lock a user out of the system,
one has only to set their password to an empty string, using either
the web interface or direct SQL manipulation of the USER table.
Note also that the password field is
essentially ignored for the special users named "anonymous", "developer",
"reader", and "nobody".  It is not possible to authenticate as users
"developer", "reader", or "nobody" and the authentication protocol
for "anonymous" uses one-time captchas not persistent passwords.

<h2>Web Interface Authentication</h2>

When a user logs into Fossil using the web interface, the login name
and password are sent in the clear to the server.  The server then
hashes the password and compares it against the value stored in USER.PW.
If they match, the server sets a cookie on the client to record the
login.  This cookie contains a large amount of high-quality randomness
and is thus intractable to guess.  The value of the cookie and the IP
address of the client is stored in the USER.COOKIE and USER.IPADDR fields
of the USER table on the server.
The USER.CEXPIRE field holds an expiration date
for the cookie, encoded as a julian day number.  On all subsequent
HTTP requests, the cookie value is matched against the USER table to
enable access to the repository.

A login cookie will only work if the IP address matches.  This feature
is designed to make it more difficult for an attacker to sniff the cookie
and take over the connection.  A cookie-sniffing attack will only work
if the attacker is able to send and receive from the same IP address as
the original login.  However, we found that doing an exact IP match
caused problems for some users who are behind proxy firewalls where the proxy
might use a different IP address for each query.  To work around this
problem, newer versions of fossil only check the first 16 bits of the
32-bit IP address.  This makes a cookie sniffing attack easier since now
the attacker only has to send and receive from any IP address in a range
of IPs that are similar to the initial login.  But that is seen as an
acceptable compromise in exchange for ease of use.  If higher security
is really needed, then HTTPS can be used instead of HTTP.

Note that in order to log into a Fossil server, it is necessary to
write information into the repository database.  Hence, login is not
possible on a Fossil repository with a read-only database file.

The user password is sent over the wire as cleartext on the initial
login attempt.  The plan moving forward is to compute the SHA1 hash of
the password on the client using javascript and then send only the hash
over the wire, but that plan has not yet been set in code.

<h2>Sync Protocol Authentication</h2>

A different authentication mechanism is used when one repository wants
to sync (or push or pull or clone) another repository.  When two
repositories are syncing, the one that initiates the transaction is
the client and the repository that responds is the server.  The client
works by sending HTTP requests to the server with a method of "xfer"
and a content-type of "application/x-fossil".  The content is Zlib-compressed
text consisting of "cards" of instructions.  The first card of this content
is a "login" card responsible for authentication.  The login card contains
the login name of the user and a "signature" where the signature is the
SHA1 hash of a nonce and the value of USER.PW.  The nonce is the
SHA1 hash of the remainder of the request content after the newline
(ASCII 14) character that terminates the login card.

Using this approach, the USER.PW value is treated as a shared secret
between the client and server.  The USER.PW value is never sent over
the wire, but the protocol establishes that both client and server know
the value of USER.PW.  Furthermore, the use of a SHA1 hash over the entire
message prevents an attacker from sniffing a valid login from a legitimate
users and then replaying the message modified content.

If the USER.PW on the server holds a cleartext password, then the
server will also accept a login-card signature that is constructed
using either the cleartext password or the SHA1 hash of the password.
This means that when USER.PW holds a cleartext password, the login card
will work for both older and newer clients.  If the USER.PW on the server
only holds the SHA1 hash of the password, then only newer clients will be
able to authenticate to the server.

The client normally gets the login and password from the "remote URL".

<blockquote><pre>
http://<span style="color:blue">login:password</span>@servername.org/path
</pre></blockquote>

For older clients, the password is used for the shared secret as stated
in the URL and with no encoding.
For newer clients, the shared secret is derived from the password
by transformed the password using the SHA1 hash encoding
described above.  However, if the first character of the password is
"*" (ASCII 0x2a) then the "*" is skipped and the rest of the password
is used directly as the share secret without the SHA1 encoding.

<blockquote><pre>
http://<span style="color:blue">login:*password</span>@servername.org/path
</pre></blockquote>

This *-before-the-password trick can be used by newer clients to
sync against a legacy server that does not understand the new SHA1
password encoding.