Skip to content

Commit

Permalink
Implement crypt_checksalt.
Browse files Browse the repository at this point in the history
This function can be used by portable users of libxcrypt to
check whether the desired hash method is supported.

There are future plans to extend the crypt_checksalt function
to check the given setting string against the configuration in
'/etc/crypt.conf' and report whether the hashing method and
parameters it specifies are acceptable.
  • Loading branch information
besser82 committed Nov 8, 2018
1 parent 1e60f98 commit 49fc32d
Show file tree
Hide file tree
Showing 10 changed files with 283 additions and 7 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
/test-badsetting
/test-bigcrypt
/test-byteorder
/test-checksalt
/test-compile-strong-alias
/test-crypt-badargs
/test-crypt-bcrypt
Expand Down
3 changes: 2 additions & 1 deletion LICENSING
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ source tree. For specific licensing terms consult the files themselves.
crypt-scrypt.c

* Copyright Björn Esser; 0-clause BSD:
crypt-common.c test-compile-strong-alias.c test-short-outbuf.c
crypt-common.c, test-checksalt.c, test-compile-strong-alias.c,
test-short-outbuf.c

* Copyright Michael Bretterklieber, Björn Esser et al.; 2-clause BSD:
crypt-nthash.c
Expand Down
6 changes: 4 additions & 2 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ EXTRA_DIST = \

notrans_dist_man3_MANS = \
crypt.3 crypt_r.3 crypt_ra.3 crypt_rn.3 \
crypt_gensalt.3 crypt_gensalt_ra.3 crypt_gensalt_rn.3
crypt_checksalt.3 crypt_gensalt.3 crypt_gensalt_ra.3 \
crypt_gensalt_rn.3
notrans_dist_man5_MANS = crypt.5

nodist_include_HEADERS = crypt.h
Expand Down Expand Up @@ -170,7 +171,7 @@ check_PROGRAMS = \
test-alg-des test-alg-gost3411-2012 test-alg-gost3411-2012-hmac \
test-alg-hmac-sha1 test-alg-md4 test-alg-md5 \
test-alg-pbkdf-hmac-sha256 test-alg-sha1 test-alg-sha256 \
test-alg-sha512 test-crypt-bcrypt test-crypt-des \
test-alg-sha512 test-checksalt test-crypt-bcrypt test-crypt-des \
test-crypt-gost-yescrypt test-crypt-md5 test-crypt-nthash \
test-crypt-pbkdf1-sha1 test-crypt-scrypt test-crypt-sha256 \
test-crypt-sha512 test-crypt-sunmd5 test-crypt-yescrypt \
Expand Down Expand Up @@ -220,6 +221,7 @@ test_crypt_yescrypt_LDADD = crypt-common.lo libcrypt.la
test_badsalt_LDADD = crypt-common.lo libcrypt.la
test_badsetting_LDADD = crypt-common.lo libcrypt.la
test_gensalt_LDADD = crypt-common.lo libcrypt.la
test_checksalt_LDADD = crypt-common.lo libcrypt.la
test_des_obsolete_LDADD = crypt-common.lo libcrypt.la
test_des_obsolete_r_LDADD = crypt-common.lo libcrypt.la
test_crypt_badargs_LDADD = crypt-common.lo libcrypt.la
Expand Down
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Version 4.3.0
output generated by descrypt under the same conditions.
This only applies when the descrypt hash method is not selected
at compile time.
* Implement crypt_checksalt, which can be used by portable users of
libxcrypt to check whether the desired hash method is supported.

Version 4.2.3
* Add bootstrap script. If building from a Git checkout instead of a
Expand Down
19 changes: 19 additions & 0 deletions crypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -334,3 +334,22 @@ crypt_gensalt_ra (const char *prefix, unsigned long count,
}
SYMVER_crypt_gensalt_ra;
#endif

#if INCLUDE_crypt_checksalt
int
crypt_checksalt (const char *setting)
{
int retval = CRYPT_SALT_INVALID;

if (!setting)
return retval;

const struct hashfn *h = get_hashfn (setting);

if (h)
retval = CRYPT_SALT_OK;

return retval;
}
SYMVER_crypt_checksalt;
#endif
20 changes: 19 additions & 1 deletion crypt.h.in.in
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,29 @@ extern char *crypt_gensalt_ra (const char *__prefix, unsigned long __count,
const char *__rbytes, int __nrbytes)
__THROW;

/* Checks whether the given setting is a supported method.

The return value is 0 if there is nothing wrong with this setting.
Otherwise, it is one of the following constants. */
extern int crypt_checksalt (const char *__setting);

/* Constants for checking the return value of the
crypt_checksalt function. */
#define CRYPT_SALT_OK 0
#define CRYPT_SALT_INVALID 1
#define CRYPT_SALT_METHOD_DISABLED 2 /* NOT implemented, yet. */
#define CRYPT_SALT_METHOD_LEGACY 3 /* NOT implemented, yet. */
#define CRYPT_SALT_TOO_CHEAP 4 /* NOT implemented, yet. */

/* These macros could be checked by portable users of crypt_gensalt*
functions to find out whether null pointers could be specified
as PREFIX and RBYTES arguments. */
#define CRYPT_GENSALT_IMPLEMENTS_DEFAULT_PREFIX 1
#define CRYPT_GENSALT_IMPLEMENTS_AUTO_ENTROPY 1
#define CRYPT_GENSALT_IMPLEMENTS_AUTO_ENTROPY 1

/* These macros can be checked by portable users of the crypt_checksalt
function to find out whether the function is implemented. */
#define CRYPT_CHECKSALT_AVAILABLE 1

/* Version number split in single integers. */
#define XCRYPT_VERSION_MAJOR @XCRYPT_VERSION_MAJOR@
Expand Down
97 changes: 97 additions & 0 deletions crypt_checksalt.3
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
.\" Written by Zack Weinberg <zackw at panix.com> in 2018.
.\"
.\" To the extent possible under law, the authors have waived
.\" all copyright and related or neighboring rights to this work.
.\" See https://creativecommons.org/publicdomain/zero/1.0/ for further
.\" details.
.\"
.Dd November 8, 2018
.Dt CRYPT_CHECKSALT 3
.Os "libxcrypt"
.Sh NAME
.Nm crypt_checksalt
.Nd validate a crypt setting string
.Sh LIBRARY
.Lb libcrypt
.Sh SYNOPSIS
.In crypt.h
.Ft int
.Fo crypt_checksalt
.Fa "const char *setting"
.Fc
.Sh DESCRIPTION
.Nm
checks the
.Ar setting
string against the configuration in
.Pa /etc/crypt.conf
and reports whether the hashing method and parameters it specifies
are acceptable.
It is intended to be used by programs
such as
.Xr login 1
to determine whether the user's passphrase should be re-hashed
using the currently preferred hashing method.
.Sh RETURN VALUES
The return value is 0 if there is nothing wrong with this setting.
Otherwise, it is one of the following constants:
.Bl -tag -width 4n
.It Dv CRYPT_SALT_INVALID
.Ar setting
is not a valid setting string; either it specifies a hashing method
that is not known to this version of libxcrypt,
or it specifies invalid parameters for the method.
.It Dv CRYPT_SALT_METHOD_DISABLED
.Ar setting
specifies a hashing method that is no longer allowed to be used at all;
.Nm crypt
will fail if passed this
.Ar setting .
Manual intervention will be required to reactivate the user's account.
.It Dv CRYPT_SALT_METHOD_LEGACY
.Ar setting
specifies a hashing method that is no longer considered strong enough
for use with new passphrases.
.Nm crypt
will still authenticate a passphrase against this setting,
but if authentication succeeds,
the passphrase should be re-hashed using the currently preferred method.
.It Dv CRYPT_SALT_TOO_CHEAP
.Ar setting
specifies cost parameters that are considered too cheap for use with
new passphrases.
.Nm crypt
will still authenticate a passphrase against this setting,
but if authentication succeeds,
the passphrase should be re-hashed using the currently preferred method.
.El
.Sh FEATURE TEST MACROS
.In crypt.h
will define the macro
.Dv CRYPT_CHECKSALT_AVAILABLE
if
.Nm
is available in the current version of libxcrypt.
.Sh PORTABILITY NOTES
The function
.Nm
is not part of any standard.
It was added to libxcrypt in version 4.3.0.
.Sh ATTRIBUTES
For an explanation of the terms used in this section, see
.Xr attributes 7 .
.TS
allbox;
lb lb lb
l l l.
Interface Attribute Value
T{
.Nm
T} Thread safety MT-Safe
.TE
.sp
.Sh SEE ALSO
.Xr crypt 3 ,
.Xr crypt_gensalt 3 ,
.Xr crypt 5 ,
.Xr crypt.conf 5
4 changes: 2 additions & 2 deletions gen-vers.awk
Original file line number Diff line number Diff line change
Expand Up @@ -177,14 +177,14 @@ END {
v = VCHAIN[i]
if ((v, sym) in symset) {
if (seq == 0) {
if (compat_only[sym] || includesym[sym] > 1) {
if (compat_only[sym] || includesym[sym] > 0) {
printf("#ifdef PIC\n#define %s _crypt_%s\n#endif\n",
sym, sym);
}
printf("#define SYMVER_%s \\\n", sym)
if (compat_only[sym]) {
printf(" symver_compat0 (\"%s\", %s, %s)", sym, sym, v)
} else if (includesym[sym] > 1) {
} else if (includesym[sym] > 0) {
printf(" symver_default (\"%s\", %s, %s)", sym, sym, v)
} else {
# Due to what appears to be a bug in GNU ld,
Expand Down
5 changes: 4 additions & 1 deletion libcrypt.map.in
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ crypt_gensalt_rn XCRYPT_2.0 GLIBC_2.0:owl:suse GLIBC_2.2.1:alt OW_CRYPT_1.0:
crypt_ra XCRYPT_2.0 GLIBC_2.0:owl:suse GLIBC_2.2.2:alt
crypt_gensalt_ra XCRYPT_2.0 GLIBC_2.0:owl:suse GLIBC_2.2.2:alt OW_CRYPT_1.0:suse

# Actively supported interfaces from libxcrypt.
crypt_checksalt XCRYPT_4.3

# Deprecated interfaces, POSIX and otherwise; also present in GNU libc
# since 2.0
encrypt - GLIBC_2.0
Expand All @@ -31,4 +34,4 @@ fcrypt - GLIBC_2.0
%chain GLIBC_2.0 GLIBC_2.2 GLIBC_2.2.1 GLIBC_2.2.2 GLIBC_2.2.5 GLIBC_2.3
%chain GLIBC_2.4 GLIBC_2.12 GLIBC_2.16 GLIBC_2.17 GLIBC_2.18 GLIBC_2.21
%chain GLIBC_2.27
%chain OW_CRYPT_1.0 XCRYPT_2.0
%chain OW_CRYPT_1.0 XCRYPT_2.0 XCRYPT_4.3
133 changes: 133 additions & 0 deletions test-checksalt.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/* Copyright (C) 2018 Björn Esser <[email protected]>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

#include "crypt-port.h"
#include <stdio.h>

struct testcase
{
const char *prefix;
const int expected_output;
};

static const struct testcase testcases[] =
{
#if INCLUDE_descrypt || INCLUDE_bigcrypt
{ "", CRYPT_SALT_OK },
{ "..", CRYPT_SALT_OK },
{ "MN", CRYPT_SALT_OK },
#else
{ "", CRYPT_SALT_INVALID },
{ "..", CRYPT_SALT_INVALID },
{ "MN", CRYPT_SALT_INVALID },
#endif
#if INCLUDE_bsdicrypt
{ "_", CRYPT_SALT_OK },
#else
{ "_", CRYPT_SALT_INVALID },
#endif
#if INCLUDE_md5crypt
{ "$1$", CRYPT_SALT_OK },
#else
{ "$1$", CRYPT_SALT_INVALID },
#endif
#if INCLUDE_nt
{ "$3$", CRYPT_SALT_OK },
#else
{ "$3$", CRYPT_SALT_INVALID },
#endif
#if INCLUDE_sunmd5
{ "$md5", CRYPT_SALT_OK },
#else
{ "$md5", CRYPT_SALT_INVALID },
#endif
#if INCLUDE_sha1crypt
{ "$sha1", CRYPT_SALT_OK },
#else
{ "$sha1", CRYPT_SALT_INVALID },
#endif
#if INCLUDE_sha256crypt
{ "$5$", CRYPT_SALT_OK },
#else
{ "$5$", CRYPT_SALT_INVALID },
#endif
#if INCLUDE_sha512crypt
{ "$6$", CRYPT_SALT_OK },
#else
{ "$6$", CRYPT_SALT_INVALID },
#endif
#if INCLUDE_bcrypt
{ "$2a$", CRYPT_SALT_OK },
{ "$2b$", CRYPT_SALT_OK },
{ "$2x$", CRYPT_SALT_OK },
{ "$2y$", CRYPT_SALT_OK },
#else
{ "$2a$", CRYPT_SALT_INVALID },
{ "$2b$", CRYPT_SALT_INVALID },
{ "$2x$", CRYPT_SALT_INVALID },
{ "$2y$", CRYPT_SALT_INVALID },
#endif
#if INCLUDE_yescrypt
{ "$y$", CRYPT_SALT_OK },
#else
{ "$y$", CRYPT_SALT_INVALID },
#endif
#if INCLUDE_scrypt
{ "$7$", CRYPT_SALT_OK },
#else
{ "$7$", CRYPT_SALT_INVALID },
#endif
#if INCLUDE_gost_yescrypt
{ "$gy$", CRYPT_SALT_OK },
#else
{ "$gy$", CRYPT_SALT_INVALID },
#endif

/* All of these are invalid. */
{ "$@", CRYPT_SALT_INVALID },
{ "%A", CRYPT_SALT_INVALID },
{ "A%", CRYPT_SALT_INVALID },
{ "$2$", CRYPT_SALT_INVALID },
{ "*0", CRYPT_SALT_INVALID },
{ "*1", CRYPT_SALT_INVALID },
{ NULL, CRYPT_SALT_INVALID }
};

int
main (void)
{
int status = 0;
int retval = 0;

for (size_t i = 0; i < ARRAY_SIZE (testcases); i++)
{
retval = crypt_checksalt (testcases[i].prefix);
if (retval == testcases[i].expected_output)
printf ("PASS | %7s | result: %d\n",
testcases[i].prefix, retval);
else
{
status = 1;
printf ("FAIL | %7s | expected: %d | got: %d\n",
testcases[i].prefix,
testcases[i].expected_output, retval);
}
}

return status;
}

0 comments on commit 49fc32d

Please sign in to comment.