Age | Commit message (Collapse) | Author | Files | Lines |
|
There are enough files now that it’s getting confusing to have
everything at the top level. Create subdirectories ‘lib’, ‘doc’, and
‘test’. Move all of the code linked into libcrypt.a into ‘lib’. Move
all the manpages into ‘doc’. Move all of the test programs into ‘test’.
There is still only one Makefile at top level. Automake doesn’t make
nonrecursive makefiles as easy as it could, but everything that was
written in http://aegis.sourceforge.net/auug97.pdf back in 1997(!) is
still true.
https://www.microsoft.com/en-us/research/wp-content/uploads/2016/03/hadrian.pdf
has an interesting counterpoint but I don’t think we’re anywhere near
the scale where those problems are relevant.
|
|
|
|
|
|
|
|
Thus we now have a md5 implementation in the public domain.
|
|
While working on something else, I discovered that crypt_gensalt would
divide by zero and crash if passed prefix="$sha1" and rounds<4.
This was easy to fix, but while writing tests for similar problems,
I discovered that the handling of out-of-range cost parameters was
inconsistent among all the hash methods.
The behavior is now:
- for hashes with a fixed cost parameter (DES/trad, DES/big, NTHASH,
MD5/bsd), crypt_gensalt only accepts 0 as the rounds argument.
- for hashes with a linear cost parameter (DES/bsdi, MD5/sun, SHA1,
SHA256, SHA512), crypt_gensalt accepts 0 or any value in the range
[1, ULONG_MAX] and clips it to the actual valid range for the hash
function, if necessary. In the case of DES/bsdi, even numbers
become odd, as well.
- for hashes with an exponential cost parameter (bcrypt),
crypt_gensalt only accepts 0 or a value in the actual valid range.
- the documented valid range for SHA1 is now [4, 4294967295] instead
of [1, 4294967295].
- all of this is tested.
|
|
This patch introduces the following semantics for NULL or invalid
`phrase` and `setting` arguments to the `crypt*` functions:
- If `setting` is NULL, all of the functions will fail (in their
usual manner) with errno set to EINVAL, regardless of what `phrase`
is. (For crypt_r/rn/ra, problems with the `data` argument may be
detected first.)
- If `setting` is a valid string (in the sense that calling `strlen`
on it will not crash the program), but `phrase` is NULL, again all
of the functions will fail with errno set to EINVAL.
- If both `setting` and `phrase` are non-NULL, and one of them is an
_invalid_ string (in the sense that calling `strlen` on it _will_
crash the program), then the program will crash. The crash is
guaranteed to happen before any code from a hashing method is executed.
- If `phrase` is NULL and `setting` is an invalid string, then it is
unspecified whether the function will fail or whether the program
will crash, but it will be one of those two things, and, again, no
code from a hashing method will be executed. (The actual behavior
right now is that the function will fail *unless* `setting` is
non-NULL and there are fewer than two readable bytes at that memory
location, but I don't want to make that a contract.)
I would somewhat prefer the simpler semantics of always crashing on
NULL as well as on invalid strings, but there was some sentiment in
favor of returning failure for NULL, so I've done this to the maximum
extent that is practical. The complicated behavior when `phrase` is
NULL but `setting` is invalid is not practical to avoid without
breaking an existing guarantee, viz. that a "failure token" never
compares equal to the `setting` string, no matter what; I think that
guarantee is significantly more important than corner-case behavior
like this.
Note also that we have __nonnull annotations on all the pointer
arguments to all these functions, which means the C compiler
unconditionally treats passing NULL as any of those arguments as
provoking undefined behavior; I actually had to make crypt-port.h
suppress those annotations when building the library, in order to
get the tests to pass.
|
|
- more fixes for crypt-sunmd5.c when 'unsigned long' and 'unsigned
int' are the same
- test-getrandom-fallbacks needs to interpose open64 as well as open
- test-short-outbuf.c can use %zu instead of %lu to avoid casting
- glibc for x86-64/-m32 uses the same symbol versions as glibc/i386
also, libcrypt.minver is now in alphabetical order by host_cpu pattern
within each block of architectures with the same minimum symbol version.
|
|
|
|
We were not adequately testing invalid-argument error paths within
crypt_gensalt, and we were also not adequately testing a variety of
corner cases related to non-default round parameters
After this change, I believe that all of the non-covered lines fall
into three categories: genuinely impossible to hit from the public
API (usually these are double-checks for preconditions already
verified at a higher level); checks for memory allocation failure; and
fallback paths within get_random_bytes. The first two of these, IMHO,
are fine to leave as is. It would probably be worth writing a test
that exercises the get_random_bytes fallbacks but it'd involve getting
one's hands dirty with ELF. I may do it eventually if no one else does.
This change makes us pickier about non-default round parameters to $5$
and $6$ hashes; numbers outside the valid range are now rejected, as
are numbers with leading zeroes and an explicit request for the
default number of rounds. This is in keeping with the observation, in
the Passlib documentation, that allowing more than one valid crypt
output string for any given (rounds, salt, phrase) triple is asking
for trouble.
This partially reverts commit
a7f9df50cecec46bb8176382faa685ce35ca72be, which accidentally caused us
to fail to reject invalid DES setting strings. Because of this, a few
lines in crypt-des.c cease to be covered; they are in category
1 (double-checks of preconditions).
|
|
This eliminates all CDDL-licensed code from the library, as requested
in issue #7 because of GPL incompatibility.
The new implementation was based exclusively on the prose description
of the algorithm in the Passlib v1.7.1 documentation, which should be
adequately arms-length for copyright purposes. (N.B. the lengthy
quotation from _Hamlet_ is used as input to MD5, so it must remain
byte-for-byte identical to achieve interoperability with the original;
also, the play itself is in the public domain.)
The new implementation is also fully deterministic (that is, its
gensalt procedure draws randomness only from its rbytes argument) and
does not call malloc.
|
|
This started out as a patch to fold together test-crypt-badsalt.c and
test-crypt-nonnull.c (which were almost the same program) and extend
their testing from DES to all of the supported hashes. That revealed
that many of the supported hash functions do not validate the contents
of their salt strings very carefully.
This patch has a low but nonzero backward compatibility risk, because
now we reject certain calls to crypt*() that we would previously have
accepted. In particular, setting strings of the form
$5$xxxxxxx*xxxxxxxx$
where x stands for any "itoa64" character and * for any non-"itoa64"
character, would formerly be accepted but are now rejected. Some of
the hash algorithms that were lenient about the contents of the salt
would echo back the salt verbatim, and others would convert it to the
base64 alphabet somehow. I think it's unlikely that this occurs in
real password files but I don't have a lot of data to base that on.
|
|
The table of supported hash algorithms now lives in hashes.lst.
The configure script accepts an option --enable-hashes which takes a
comma-separated list of hash algorithms to include. We generate a
header that defines INCLUDE_ macros for each hash that is enabled,
and all of the code is conditionalized appropriately.
The default is --enable-hashes=all. --enable-hashes=strong is the
equivalent of the old --disable-weak-hashes. You could even do
--enable-hashes=bcrypt,des to get a binary-compatible libcrypt.so.1
that still supports almost nothing other than bcrypt.
|
|
|
|
|
|
|
|
This algorithm was developed by Alec Muffett for Solaris, as a
replacement for the aging des_crypt. It was introduced in Solaris
9u2. While based on the MD5 message digest, it has very little at
all in common with the md5_crypt algorithm. It supports 32 bit
variable rounds and an 8 character salt.
The gensalt() function for this algorithm is modified to always
return a new setting with a sane, but random, default amount of
rounds for the corresponding crypt() function. Besides this it
follows the original implementation from (Open)Solaris.
Its use is not recommended, as today it is easily broken.
|