|
Packit |
13e0ca |
/* Test rejection of ill-formed setting strings.
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
Written by Zack Weinberg <zackw at panix.com> in 2018.
|
|
Packit |
13e0ca |
To the extent possible under law, Zack Weinberg has waived all
|
|
Packit |
13e0ca |
copyright and related or neighboring rights to this work.
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
See https://creativecommons.org/publicdomain/zero/1.0/ for further
|
|
Packit |
13e0ca |
details. */
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
#include "crypt-port.h"
|
|
Packit |
13e0ca |
#include <crypt.h>
|
|
Packit |
13e0ca |
#include <errno.h>
|
|
Packit |
13e0ca |
#include <stdio.h>
|
|
Packit |
13e0ca |
#include <stdlib.h>
|
|
Packit |
13e0ca |
#include <string.h>
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* Supply 64 bytes of "random" data to each gensalt call, for
|
|
Packit |
13e0ca |
determinism. */
|
|
Packit |
13e0ca |
static const char rbytes[] =
|
|
Packit |
13e0ca |
"yC8S8E7o+tmofM3L3DgKRwBy+RjWygAXIda7CAghZeXR9ZSl0UZh3kvt2XHg+aKo";
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
struct testcase
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
const char *prefix;
|
|
Packit |
13e0ca |
unsigned long count;
|
|
Packit |
13e0ca |
int rbytes; /* 0 = use sizeof rbytes - 1 */
|
|
Packit |
13e0ca |
int osize; /* 0 = use CRYPT_GENSALT_OUTPUT_SIZE */
|
|
Packit |
13e0ca |
};
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* For each included hash, test malformed versions of its prefix
|
|
Packit |
13e0ca |
and invalid combinations of other arguments to gensalt.
|
|
Packit |
13e0ca |
For each excluded hash, test that a correct gensalt invocation
|
|
Packit |
13e0ca |
will still be rejected. */
|
|
Packit |
13e0ca |
static const struct testcase testcases[] = {
|
|
Packit |
13e0ca |
/* DES (traditional and/or bigcrypt) -- count is ignored */
|
|
Packit |
13e0ca |
#if INCLUDE_des || INCLUDE_des_big
|
|
Packit |
13e0ca |
{ "!a", 0, 0, 0 }, // invalid first character
|
|
Packit |
13e0ca |
{ "a!", 0, 0, 0 }, // invalid second character
|
|
Packit |
13e0ca |
{ "xx", 1, 0, 0 }, // doesn't accept variable counts
|
|
Packit |
13e0ca |
{ "xx", 0, 1, 0 }, // inadequate rbytes
|
|
Packit |
13e0ca |
{ "xx", 0, 0, 1 }, // inadequate osize
|
|
Packit |
13e0ca |
#else
|
|
Packit |
13e0ca |
{ "", 0, 0, 0 },
|
|
Packit |
13e0ca |
{ "xx", 0, 0, 0 },
|
|
Packit |
13e0ca |
#endif
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* BSDi extended DES */
|
|
Packit |
13e0ca |
#if INCLUDE_des_xbsd
|
|
Packit |
13e0ca |
{ "_", 2, 0, 0 }, // even number
|
|
Packit |
13e0ca |
{ "_", 16777217, 0, 0 }, // too large
|
|
Packit |
13e0ca |
{ "_", 0, 2, 0 }, // inadequate rbytes
|
|
Packit |
13e0ca |
{ "_", 0, 0, 4 }, // inadequate osize
|
|
Packit |
13e0ca |
#else
|
|
Packit |
13e0ca |
{ "_", 0, 0, 0 },
|
|
Packit |
13e0ca |
#endif
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* MD5 (FreeBSD) */
|
|
Packit |
13e0ca |
#if INCLUDE_md5
|
|
Packit |
13e0ca |
{ "$1", 0, 0, 0 }, // truncated prefix
|
|
Packit |
13e0ca |
{ "$1$", 1, 0, 0 }, // doesn't accept variable counts
|
|
Packit |
13e0ca |
{ "$1$", 0, 2, 0 }, // inadequate rbytes
|
|
Packit |
13e0ca |
{ "$1$", 0, 0, 4 }, // inadequate osize
|
|
Packit |
13e0ca |
#else
|
|
Packit |
13e0ca |
{ "$1$", 0, 0, 0 },
|
|
Packit |
13e0ca |
#endif
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* MD5 (Sun) */
|
|
Packit |
13e0ca |
#if INCLUDE_sunmd5
|
|
Packit |
13e0ca |
{ "$m", 0, 0, 0 }, // truncated prefix
|
|
Packit |
13e0ca |
{ "$md", 0, 0, 0 },
|
|
Packit |
13e0ca |
{ "$md5", 4294963200, 0, 0 }, // too large
|
|
Packit |
13e0ca |
{ "$md5", 0, 2, 0 }, // inadequate rbytes
|
|
Packit |
13e0ca |
{ "$md5", 0, 0, 4 }, // inadequate osize
|
|
Packit |
13e0ca |
#else
|
|
Packit |
13e0ca |
{ "$md5", 0, 0, 0 },
|
|
Packit |
13e0ca |
#endif
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* NTHASH */
|
|
Packit |
13e0ca |
#if INCLUDE_nthash
|
|
Packit |
13e0ca |
{ "$3", 0, 0, 0 }, // truncated prefix
|
|
Packit |
13e0ca |
{ "$3$", 0, 0, 4 }, // inadequate osize
|
|
Packit |
13e0ca |
#else
|
|
Packit |
13e0ca |
{ "$3$", 0, 0, 0 },
|
|
Packit |
13e0ca |
#endif
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* SHA1 */
|
|
Packit |
13e0ca |
#if INCLUDE_sha1
|
|
Packit |
13e0ca |
{ "$s", 0, 0, 0 }, // truncated prefix
|
|
Packit |
13e0ca |
{ "$sh", 0, 0, 0 },
|
|
Packit |
13e0ca |
{ "$sha", 0, 0, 0 },
|
|
Packit |
13e0ca |
{ "$sha1", 0, 2, 0 }, // inadequate rbytes
|
|
Packit |
13e0ca |
{ "$sha1", 0, 0, 4 }, // inadequate osize
|
|
Packit |
13e0ca |
#else
|
|
Packit |
13e0ca |
{ "$sha1", 0, 0, 0 },
|
|
Packit |
13e0ca |
#endif
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* SHA256 */
|
|
Packit |
13e0ca |
#if INCLUDE_sha256
|
|
Packit |
13e0ca |
{ "$5", 0, 0, 0 }, // truncated prefix
|
|
Packit |
13e0ca |
{ "$5$", 999, 0, 0 }, // too small
|
|
Packit |
13e0ca |
{ "$5$", 1000000000, 0, 0 }, // too large
|
|
Packit |
13e0ca |
{ "$5$", 0, 2, 0 }, // inadequate rbytes
|
|
Packit |
13e0ca |
{ "$5$", 0, 0, 4 }, // inadequate osize
|
|
Packit |
13e0ca |
#else
|
|
Packit |
13e0ca |
{ "$5$", 0, 0, 0 },
|
|
Packit |
13e0ca |
#endif
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* SHA512 */
|
|
Packit |
13e0ca |
#if INCLUDE_sha512
|
|
Packit |
13e0ca |
{ "$6", 0, 0, 0 }, // truncated prefix
|
|
Packit |
13e0ca |
{ "$6$", 999, 0, 0 }, // too small
|
|
Packit |
13e0ca |
{ "$6$", 1000000000, 0, 0 }, // too large
|
|
Packit |
13e0ca |
{ "$6$", 0, 2, 0 }, // inadequate rbytes
|
|
Packit |
13e0ca |
{ "$6$", 0, 0, 4 }, // inadequate osize
|
|
Packit |
13e0ca |
#else
|
|
Packit |
13e0ca |
{ "$6$", 0, 0, 0 },
|
|
Packit |
13e0ca |
#endif
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* bcrypt */
|
|
Packit |
13e0ca |
#if INCLUDE_bcrypt
|
|
Packit |
13e0ca |
{ "$2", 0, 0, 0 }, // truncated prefix
|
|
Packit |
13e0ca |
{ "$2a", 0, 0, 0 },
|
|
Packit |
13e0ca |
{ "$2b", 0, 0, 0 },
|
|
Packit |
13e0ca |
{ "$2x", 0, 0, 0 },
|
|
Packit |
13e0ca |
{ "$2y", 0, 0, 0 },
|
|
Packit |
13e0ca |
{ "$2b$", 3, 0, 0 }, // too small
|
|
Packit |
13e0ca |
{ "$2b$", 32, 0, 0 }, // too large
|
|
Packit |
13e0ca |
{ "$2b$", 0, 2, 0 }, // inadequate rbytes
|
|
Packit |
13e0ca |
{ "$2b$", 0, 0, 4 }, // inadequate osize
|
|
Packit |
13e0ca |
#else
|
|
Packit |
13e0ca |
{ "$2a$", 0, 0, 0 },
|
|
Packit |
13e0ca |
{ "$2b$", 0, 0, 0 },
|
|
Packit |
13e0ca |
{ "$2x$", 0, 0, 0 },
|
|
Packit |
13e0ca |
{ "$2y$", 0, 0, 0 },
|
|
Packit |
13e0ca |
#endif
|
|
Packit |
13e0ca |
};
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
static void
|
|
Packit |
13e0ca |
print_escaped_string (const char *s)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
putchar ('"');
|
|
Packit |
13e0ca |
for (const char *p = s; *p; p++)
|
|
Packit |
13e0ca |
if (*p >= ' ' && *p <= '~')
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
if (*p == '\\' || *p == '\"')
|
|
Packit |
13e0ca |
putchar ('\\');
|
|
Packit |
13e0ca |
putchar (*p);
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
else
|
|
Packit |
13e0ca |
printf ("\\x%02x", (unsigned int)(unsigned char)*p);
|
|
Packit |
13e0ca |
putchar ('"');
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
static bool error_occurred = false;
|
|
Packit |
13e0ca |
static void
|
|
Packit |
13e0ca |
report_error (const char *fn, const struct testcase *tc,
|
|
Packit |
13e0ca |
int err, const char *output)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
error_occurred = true;
|
|
Packit |
13e0ca |
printf ("%s(", fn);
|
|
Packit |
13e0ca |
print_escaped_string (tc->prefix);
|
|
Packit |
13e0ca |
printf (", %lu, nrbytes=%d, osize=%d):\n", tc->count,
|
|
Packit |
13e0ca |
tc->rbytes > 0 ? tc->rbytes : (int) sizeof rbytes - 1,
|
|
Packit |
13e0ca |
tc->osize > 0 ? tc->osize : CRYPT_GENSALT_OUTPUT_SIZE);
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
if (output)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
if (err)
|
|
Packit |
13e0ca |
printf ("\toutput with errno = %s\n", strerror (err));
|
|
Packit |
13e0ca |
printf ("\texpected NULL, got ");
|
|
Packit |
13e0ca |
print_escaped_string (output);
|
|
Packit |
13e0ca |
putchar ('\n');
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
else if (err != (tc->osize > 0 ? ERANGE : EINVAL))
|
|
Packit |
13e0ca |
printf ("\tno output with errno = %s\n",
|
|
Packit |
13e0ca |
err ? strerror (err) : "0");
|
|
Packit |
13e0ca |
else
|
|
Packit |
13e0ca |
printf ("\tno output with errno = %s"
|
|
Packit |
13e0ca |
"(shouldn't have been called)\n", strerror (err));
|
|
Packit |
13e0ca |
putchar ('\n');
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
static void
|
|
Packit |
13e0ca |
test_one (const struct testcase *tc)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
char obuf[CRYPT_GENSALT_OUTPUT_SIZE];
|
|
Packit |
13e0ca |
char *s;
|
|
Packit |
13e0ca |
int nrbytes = tc->rbytes > 0 ? tc->rbytes : (int)(sizeof rbytes - 1);
|
|
Packit |
13e0ca |
int osize = tc->osize > 0 ? tc->osize : CRYPT_GENSALT_OUTPUT_SIZE;
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* It is only possible to provide a variant osize to crypt_gensalt_rn. */
|
|
Packit |
13e0ca |
if (tc->osize == 0)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
errno = 0;
|
|
Packit |
13e0ca |
s = crypt_gensalt (tc->prefix, tc->count, rbytes, nrbytes);
|
|
Packit |
13e0ca |
if (s || errno != EINVAL)
|
|
Packit |
13e0ca |
report_error ("gensalt", tc, errno, s);
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
errno = 0;
|
|
Packit |
13e0ca |
s = crypt_gensalt_ra (tc->prefix, tc->count, rbytes, nrbytes);
|
|
Packit |
13e0ca |
if (s || errno != EINVAL)
|
|
Packit |
13e0ca |
report_error ("gensalt_ra", tc, errno, s);
|
|
Packit |
13e0ca |
free (s);
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
errno = 0;
|
|
Packit |
13e0ca |
s = crypt_gensalt_rn (tc->prefix, tc->count, rbytes, nrbytes, obuf, osize);
|
|
Packit |
13e0ca |
if (s || errno != (tc->osize > 0 ? ERANGE : EINVAL))
|
|
Packit |
13e0ca |
report_error ("gensalt_rn", tc, errno, s);
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* All single-character strings (except "_" when BSDi extended DES
|
|
Packit |
13e0ca |
is enabled) are invalid prefixes, either because the character
|
|
Packit |
13e0ca |
cannot be the first character of any valid prefix, or because the
|
|
Packit |
13e0ca |
string is too short. */
|
|
Packit |
13e0ca |
static void
|
|
Packit |
13e0ca |
test_single_characters (void)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
char s[2];
|
|
Packit |
13e0ca |
struct testcase tc;
|
|
Packit |
13e0ca |
s[1] = '\0';
|
|
Packit |
13e0ca |
tc.prefix = s;
|
|
Packit |
13e0ca |
tc.count = 0;
|
|
Packit |
13e0ca |
tc.rbytes = 0;
|
|
Packit |
13e0ca |
tc.osize = 0;
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
for (int i = 1; i < 256; i++)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
#ifdef INCLUDE_des_xbsd
|
|
Packit |
13e0ca |
if (i == '_') continue;
|
|
Packit |
13e0ca |
#endif
|
|
Packit |
13e0ca |
s[0] = (char)i;
|
|
Packit |
13e0ca |
test_one (&tc);
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* '$' followed by any non-ASCII-isalnum character is also always
|
|
Packit |
13e0ca |
invalid. */
|
|
Packit |
13e0ca |
static void
|
|
Packit |
13e0ca |
test_dollar_nonalphanum (void)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
char s[3];
|
|
Packit |
13e0ca |
struct testcase tc;
|
|
Packit |
13e0ca |
s[0] = '$';
|
|
Packit |
13e0ca |
s[2] = '\0';
|
|
Packit |
13e0ca |
tc.prefix = s;
|
|
Packit |
13e0ca |
tc.count = 0;
|
|
Packit |
13e0ca |
tc.rbytes = 0;
|
|
Packit |
13e0ca |
tc.osize = 0;
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
for (int i = 1; i < 256; i++)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
if (('0' >= i && i <= '9') ||
|
|
Packit |
13e0ca |
('A' >= i && i <= 'Z') ||
|
|
Packit |
13e0ca |
('a' >= i && i <= 'z'))
|
|
Packit |
13e0ca |
continue;
|
|
Packit |
13e0ca |
s[1] = (char)i;
|
|
Packit |
13e0ca |
test_one (&tc);
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
int
|
|
Packit |
13e0ca |
main(void)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
test_single_characters();
|
|
Packit |
13e0ca |
test_dollar_nonalphanum();
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* Hand-crafted arguments for each supported algorithm. */
|
|
Packit |
13e0ca |
for (size_t i = 0; i < ARRAY_SIZE (testcases); i++)
|
|
Packit |
13e0ca |
test_one (&testcases[i]);
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
return error_occurred;
|
|
Packit |
13e0ca |
}
|