https://bz.apache.org/bugzilla/show_bug.cgi?id=69852

--- Comment #7 from Grzegorz Grzybek <[email protected]> ---
Oh - I love digging in history - I had to reason about code from early 2000s to
understand the consequences in 2020s...

True - I was thinking about {SHA}xxx format for LDAP passwords. I didn't find
exact RFC, but there's
https://datatracker.ietf.org/doc/html/draft-stroeder-hashed-userpassword-values
specifying prefixes like {SHA} or even {SSHA512}.

This draft introduces this scheme:

    {<digest-alg>}<base64(password-hash salt)>

RFC 3112 LDAP Authentication Password Schema has different syntax - '$'
separated values.

Tomcat's
https://tomcat.apache.org/tomcat-11.0-doc/config/credentialhandler.html#MessageDigestCredentialHandler
defines/documents SSHA as:

    20 character salt followed by the salted SHA1 digest Base64 encoded

However in the code
https://github.com/apache/tomcat/blob/51fd0788b401d589acb9bede8cbd6a495a9ca943/java/org/apache/catalina/realm/MessageDigestCredentialHandler.java#L117
we have

    // "{SSHA}<sha-1 digest:20><salt:n>"
    ...
    // Extract the first 20 bytes containing the SHA-1 digest
    final int digestLength = 20;
    ...
    System.arraycopy(serverDigestPlusSaltBytes, 0, serverDigestBytes, 0,
digestLength);
    ...
    System.arraycopy(serverDigestPlusSaltBytes, digestLength, serverSaltBytes,
0, saltLength);

so the documentation is wrong and should be:

    20 bytes of SHA1 digest of password and the salt, followed by the salt
bytes ,Base64 encoded

Apache Directory Server also uses password+salt digest (in this order):
https://github.com/apache/directory-ldap-api/blob/master/ldap/model/src/main/java/org/apache/directory/api/ldap/model/password/PasswordUtil.java#L446-L478

And base64 encodes the hash+salt (in this order):
https://github.com/apache/directory-ldap-api/blob/be233029e53c7914d3e2588ec151c325cf54b771/ldap/model/src/main/java/org/apache/directory/api/ldap/model/password/PasswordUtil.java#L258

So here, Tomcat code, ApacheDS code and this IETF drafts are consistent, but
Tomcat documentation is not.

While I agree that using:

    <CredentialHandler
className="org.apache.catalina.realm.MessageDigestCredentialHandler"
algorithm="SHA-384" />

means that the user knows what's being done, when you're NOT configuring this
handler we can assume that tomcat-users.xml like this:

    <tomcat-users>
      <user username="tomcat" password="tomcat=" roles="..."/>
      <user username="tomcat2" password="{MD5}GzWdh1OFi1W++gRBBnqu0w=="
roles="..."/>
      <user username="tomcat3"
password="{SSHA}iVkga68v3vXOzrB7OuNiD5gzaaeOMrVbUjPdZxTGurtfZ/bpHRTvEZAFmvEvhtlFeTV0vhZZg3ZrEQ=="
roles="..."/>
    </tomcat-users>

should be fine. But it's not - passwords for tomcat2 and tomcat3 users are
compared directly because of:

    if (getAlgorithm() == null) {
      // No digests, compare directly
      return DigestCredentialHandlerBase.equals(inputCredentials,
storedCredentials, false);

Let's not discuss the strength of MD5 or using Memory/UserDatabaseRealm for
serious use. I'm just trying to clear the confusion ;)

Oh and I just tried to check
`{SSHA}iVkga68v3vXOzrB7OuNiD5gzaaeOMrVbUjPdZxTGurtfZ/bpHRTvEZAFmvEvhtlFeTV0vhZZg3ZrEQ==`
('tomcat' password with 38 bytes salt and SHA-1) and when checking the incoming
password, first the password is digested then the salt:

    // Generate the digested form of the user provided password
    // using the salt
    byte[] userDigestBytes = ConcurrentMessageDigest.digest(getAlgorithm(),
            inputCredentials.getBytes(StandardCharsets.ISO_8859_1),
serverSaltBytes);

While when checking $-separated password (salt $ ic $ digest),
org.apache.catalina.realm.MessageDigestCredentialHandler#mutate first digests
the salt and then the password...

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to