(root)/
libxcrypt-4.4.36/
test/
badsetting.c
       1  /* Test rejection of ill-formed setting strings.
       2  
       3     Written by Zack Weinberg <zackw at panix.com> in 2018.
       4     To the extent possible under law, Zack Weinberg has waived all
       5     copyright and related or neighboring rights to this work.
       6  
       7     See https://creativecommons.org/publicdomain/zero/1.0/ for further
       8     details.  */
       9  
      10  #include "crypt-port.h"
      11  
      12  #include <errno.h>
      13  #include <stdio.h>
      14  #include <stdlib.h>
      15  
      16  /* Supply 64 bytes of "random" data to each gensalt call, for
      17     determinism.  */
      18  static const char rbytes[] =
      19    "yC8S8E7o+tmofM3L3DgKRwBy+RjWygAXIda7CAghZeXR9ZSl0UZh3kvt2XHg+aKo";
      20  
      21  struct testcase
      22  {
      23    const char *prefix;
      24    unsigned long count;
      25    int rbytes;  /* 0 = use sizeof rbytes - 1 */
      26    int osize;   /* 0 = use CRYPT_GENSALT_OUTPUT_SIZE */
      27  };
      28  
      29  /* For each included hash, test malformed versions of its prefix
      30     and invalid combinations of other arguments to gensalt.
      31     For each excluded hash, test that a correct gensalt invocation
      32     will still be rejected.  */
      33  static const struct testcase testcases[] =
      34  {
      35    /* DES (traditional and/or bigcrypt) -- count is ignored */
      36  #if INCLUDE_descrypt || INCLUDE_bigcrypt
      37    { "!a", 0, 0, 0 },            // invalid first character
      38    { "a!", 0, 0, 0 },            // invalid second character
      39    { "xx", 1, 0, 0 },            // doesn't accept variable counts
      40    { "xx", 0, 1, 0 },            // inadequate rbytes
      41    { "xx", 0, 0, 1 },            // inadequate osize
      42  #else
      43    { "",   0, 0, 0 },
      44    { "xx", 0, 0, 0 },
      45  #endif
      46  
      47    /* BSDi extended DES  */
      48  #if INCLUDE_bsdicrypt
      49    { "_", 0,        2, 0 },      // inadequate rbytes
      50    { "_", 0,        0, 4 },      // inadequate osize
      51  #else
      52    { "_", 0, 0, 0 },
      53  #endif
      54  
      55    /* MD5 (FreeBSD) */
      56  #if INCLUDE_md5crypt
      57    { "$1",  0, 0, 0 },           // truncated prefix
      58    { "$1$", 1, 0, 0 },           // doesn't accept variable counts
      59    { "$1$", 0, 2, 0 },           // inadequate rbytes
      60    { "$1$", 0, 0, 4 },           // inadequate osize
      61  #else
      62    { "$1$", 0, 0, 0 },
      63  #endif
      64  
      65    /* MD5 (Sun) */
      66  #if INCLUDE_sunmd5
      67    { "$m",   0,          0, 0 }, // truncated prefix
      68    { "$md",  0,          0, 0 },
      69    { "$md5", 0,          2, 0 }, // inadequate rbytes
      70    { "$md5", 0,          0, 4 }, // inadequate osize
      71  #else
      72    { "$md5", 0, 0, 0 },
      73  #endif
      74  
      75    /* NTHASH */
      76  #if INCLUDE_nt
      77    { "$3",  0, 0, 0 },           // truncated prefix
      78    { "$3$", 1, 0, 0 },           // doesn't accept variable counts
      79    { "$3$", 0, 0, 3 },           // inadequate osize
      80  #else
      81    { "$3$", 0, 0, 0 },
      82  #endif
      83  
      84    /* SHA1 */
      85  #if INCLUDE_sha1crypt
      86    { "$s",   0, 0, 0 },          // truncated prefix
      87    { "$sh",  0, 0, 0 },
      88    { "$sha", 0, 0, 0 },
      89    { "$sha1", 0, 2, 0 },         // inadequate rbytes
      90    { "$sha1", 0, 0, 4 },         // inadequate osize
      91  #else
      92    { "$sha1", 0, 0, 0 },
      93  #endif
      94  
      95    /* SHA256 */
      96  #if INCLUDE_sha256crypt
      97    { "$5",  0,          0, 0 },  // truncated prefix
      98    { "$5$", 0,          2, 0 },  // inadequate rbytes
      99    { "$5$", 0,          0, 4 },  // inadequate osize
     100  #else
     101    { "$5$", 0, 0, 0 },
     102  #endif
     103  
     104    /* SHA512 */
     105  #if INCLUDE_sha512crypt
     106    { "$6",  0,          0, 0 },  // truncated prefix
     107    { "$6$", 0,          2, 0 },  // inadequate rbytes
     108    { "$6$", 0,          0, 4 },  // inadequate osize
     109  #else
     110    { "$6$", 0, 0, 0 },
     111  #endif
     112  
     113    /* bcrypt */
     114  #if INCLUDE_bcrypt
     115    { "$2",   0,  0, 0 },         // truncated prefix
     116    { "$2a",  0,  0, 0 },
     117    { "$2b",  0,  0, 0 },
     118    { "$2x",  0,  0, 0 },
     119    { "$2y",  0,  0, 0 },
     120    { "$2b$", 3,  0, 0 },         // too small
     121    { "$2b$", 32, 0, 0 },         // too large
     122    { "$2b$", 0,  2, 0 },         // inadequate rbytes
     123    { "$2b$", 0,  0, 4 },         // inadequate osize
     124  #else
     125    { "$2b$", 0, 0, 0 },
     126  #endif
     127  #if INCLUDE_bcrypt_a
     128    { "$2",   0,  0, 0 },         // truncated prefix
     129    { "$2a",  0,  0, 0 },
     130    { "$2b",  0,  0, 0 },
     131    { "$2x",  0,  0, 0 },
     132    { "$2y",  0,  0, 0 },
     133    { "$2a$", 3,  0, 0 },         // too small
     134    { "$2a$", 32, 0, 0 },         // too large
     135    { "$2a$", 0,  2, 0 },         // inadequate rbytes
     136    { "$2a$", 0,  0, 4 },         // inadequate osize
     137  #else
     138    { "$2a$", 0, 0, 0 },
     139  #endif
     140  #if INCLUDE_bcrypt_x
     141    { "$2",   0,  0, 0 },         // truncated prefix
     142    { "$2a",  0,  0, 0 },
     143    { "$2b",  0,  0, 0 },
     144    { "$2x",  0,  0, 0 },
     145    { "$2y",  0,  0, 0 },
     146    { "$2x$", 0,  0, 0 },         // cannot be used
     147  #else
     148    { "$2x$", 0, 0, 0 },
     149  #endif
     150  #if INCLUDE_bcrypt_y
     151    { "$2",   0,  0, 0 },         // truncated prefix
     152    { "$2a",  0,  0, 0 },
     153    { "$2b",  0,  0, 0 },
     154    { "$2x",  0,  0, 0 },
     155    { "$2y",  0,  0, 0 },
     156    { "$2y$", 3,  0, 0 },         // too small
     157    { "$2y$", 32, 0, 0 },         // too large
     158    { "$2y$", 0,  2, 0 },         // inadequate rbytes
     159    { "$2y$", 0,  0, 4 },         // inadequate osize
     160  #else
     161    { "$2y$", 0, 0, 0 },
     162  #endif
     163  
     164    /* yescrypt */
     165  #if INCLUDE_yescrypt
     166    { "$y",   0,  0, 0 },         // truncated prefix
     167    { "$y$",  32, 0, 0 },         // too large
     168    { "$y$",  0,  2, 0 },         // inadequate rbytes
     169    { "$y$",  0,  0, 4 },         // inadequate osize
     170  #else
     171    { "$y$",  0, 0, 0 },
     172  #endif
     173  
     174    /* scrypt */
     175  #if INCLUDE_scrypt
     176    { "$7",   0,  0, 0 },         // truncated prefix
     177    { "$7$",  3,  0, 0 },         // too small
     178    { "$7$",  32, 0, 0 },         // too large
     179    { "$7$",  0,  2, 0 },         // inadequate rbytes
     180    { "$7$",  0,  0, 4 },         // inadequate osize
     181  #else
     182    { "$7$",  0, 0, 0 },
     183  #endif
     184  
     185    /* gost-yescrypt */
     186  #if INCLUDE_gost_yescrypt
     187    { "$gy",  0,  0, 0 },         // truncated prefix
     188    { "$gy$", 32, 0, 0 },         // too large
     189    { "$gy$", 0,  2, 0 },         // inadequate rbytes
     190    { "$gy$", 0,  0, 4 },         // inadequate osize
     191  #else
     192    { "$gy$",  0, 0, 0 },
     193  #endif
     194  };
     195  
     196  static void
     197  print_escaped_string (const char *s)
     198  {
     199    putchar ('"');
     200    for (const char *p = s; *p; p++)
     201      if (*p >= ' ' && *p <= '~')
     202        {
     203          if (*p == '\\' || *p == '\"')
     204            putchar ('\\');
     205          putchar (*p);
     206        }
     207      else
     208        printf ("\\x%02x", (unsigned int)(unsigned char)*p);
     209    putchar ('"');
     210  }
     211  
     212  static bool error_occurred = false;
     213  static void
     214  report_error (const char *fn, const struct testcase *tc,
     215                int err, const char *output)
     216  {
     217    error_occurred = true;
     218    printf ("%s(", fn);
     219    print_escaped_string (tc->prefix);
     220    printf (", %lu, nrbytes=%d, osize=%d):\n", tc->count,
     221            tc->rbytes > 0 ? tc->rbytes : (int) sizeof rbytes - 1,
     222            tc->osize  > 0 ? tc->osize  : CRYPT_GENSALT_OUTPUT_SIZE);
     223  
     224    if (output)
     225      {
     226        if (err)
     227          printf ("\toutput with errno = %s\n", strerror (err));
     228        printf ("\texpected NULL, got ");
     229        print_escaped_string (output);
     230        putchar ('\n');
     231      }
     232    else if (err != (tc->osize > 0 ? ERANGE : EINVAL))
     233      printf ("\tno output with errno = %s\n",
     234              err ? strerror (err) : "0");
     235    else
     236      printf ("\tno output with errno = %s"
     237              "(shouldn't have been called)\n", strerror (err));
     238    putchar ('\n');
     239  }
     240  
     241  static void
     242  test_one (const struct testcase *tc)
     243  {
     244    char obuf[CRYPT_GENSALT_OUTPUT_SIZE];
     245    char *s;
     246    int nrbytes = tc->rbytes > 0 ? tc->rbytes : (int)(sizeof rbytes - 1);
     247    int osize   = tc->osize  > 0 ? tc->osize : CRYPT_GENSALT_OUTPUT_SIZE;
     248  
     249    /* It is only possible to provide a variant osize to crypt_gensalt_rn.  */
     250    if (tc->osize == 0)
     251      {
     252        errno = 0;
     253        s = crypt_gensalt (tc->prefix, tc->count, rbytes, nrbytes);
     254        if (s || errno != EINVAL)
     255          report_error ("gensalt", tc, errno, s);
     256  
     257        errno = 0;
     258        s = crypt_gensalt_ra (tc->prefix, tc->count, rbytes, nrbytes);
     259        if (s || errno != EINVAL)
     260          report_error ("gensalt_ra", tc, errno, s);
     261        free (s);
     262      }
     263  
     264    errno = 0;
     265    s = crypt_gensalt_rn (tc->prefix, tc->count, rbytes, nrbytes, obuf, osize);
     266    if (s || errno != (tc->osize > 0 ? ERANGE : EINVAL))
     267      report_error ("gensalt_rn", tc, errno, s);
     268  }
     269  
     270  /* All single-character strings (except "_" when BSDi extended DES
     271     is enabled) are invalid prefixes, either because the character
     272     cannot be the first character of any valid prefix, or because the
     273     string is too short.  */
     274  static void
     275  test_single_characters (void)
     276  {
     277    char s[2];
     278    struct testcase tc;
     279    s[1] = '\0';
     280    tc.prefix = s;
     281    tc.count = 0;
     282    tc.rbytes = 0;
     283    tc.osize = 0;
     284  
     285    for (int i = 1; i < 256; i++)
     286      {
     287  #ifdef INCLUDE_bsdicrypt
     288        if (i == '_') continue;
     289  #endif
     290        s[0] = (char)i;
     291        test_one (&tc);
     292      }
     293  }
     294  
     295  /* '$' followed by any non-ASCII-isalnum character is also always
     296     invalid.  */
     297  static void
     298  test_dollar_nonalphanum (void)
     299  {
     300    char s[3];
     301    struct testcase tc;
     302    s[0] = '$';
     303    s[2] = '\0';
     304    tc.prefix = s;
     305    tc.count = 0;
     306    tc.rbytes = 0;
     307    tc.osize = 0;
     308  
     309    for (int i = 1; i < 256; i++)
     310      {
     311        if (('0' >= i && i <= '9') ||
     312            ('A' >= i && i <= 'Z') ||
     313            ('a' >= i && i <= 'z'))
     314          continue;
     315        s[1] = (char)i;
     316        test_one (&tc);
     317      }
     318  }
     319  
     320  int
     321  main(void)
     322  {
     323    test_single_characters();
     324    test_dollar_nonalphanum();
     325  
     326    /* Hand-crafted arguments for each supported algorithm.  */
     327    for (size_t i = 0; i < ARRAY_SIZE (testcases); i++)
     328      test_one (&testcases[i]);
     329  
     330    return error_occurred;
     331  }