passwd.c 16.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
/* ====================================================================
 * Copyright (c) 2000-2015 The OpenSSL Project.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
 *
 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission. For written permission, please contact
 *    licensing@OpenSSL.org.
 *
 * 5. Products derived from this software may not be called "OpenSSL"
 *    nor may "OpenSSL" appear in their names without prior written
 *    permission of the OpenSSL Project.
 *
 * 6. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
 *
 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
 * EXPRESSED 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 OpenSSL PROJECT OR
 * ITS 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.
 * ====================================================================
 */
B
Bodo Möller 已提交
49

50
#if defined OPENSSL_NO_MD5 || defined CHARSET_EBCDIC
51
# define NO_MD5CRYPT_1
B
Bodo Möller 已提交
52 53
#endif

54
#if !defined(OPENSSL_NO_DES) || !defined(NO_MD5CRYPT_1)
B
Bodo Möller 已提交
55

56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
# include <string.h>

# include "apps.h"

# include <openssl/bio.h>
# include <openssl/err.h>
# include <openssl/evp.h>
# include <openssl/rand.h>
# ifndef OPENSSL_NO_DES
#  include <openssl/des.h>
# endif
# ifndef NO_MD5CRYPT_1
#  include <openssl/md5.h>
# endif

static unsigned const char cov_2char[64] = {
    /* from crypto/des/fcrypt.c */
    0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
    0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44,
    0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C,
    0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54,
    0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62,
    0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A,
    0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72,
    0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A
B
Bodo Möller 已提交
81 82
};

83
static int do_passwd(int passed_salt, char **salt_p, char **salt_malloc_p,
84 85 86
                     char *passwd, BIO *out, int quiet, int table,
                     int reverse, size_t pw_maxlen, int usecrypt, int use1,
                     int useapr1);
87

88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
typedef enum OPTION_choice {
    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
    OPT_IN,
    OPT_NOVERIFY, OPT_QUIET, OPT_TABLE, OPT_REVERSE, OPT_APR1,
    OPT_1, OPT_CRYPT, OPT_SALT, OPT_STDIN
} OPTION_CHOICE;

OPTIONS passwd_options[] = {
    {"help", OPT_HELP, '-', "Display this summary"},
    {"in", OPT_IN, '<', "Pead passwords from file"},
    {"noverify", OPT_NOVERIFY, '-',
     "Never verify when reading password from terminal"},
    {"quiet", OPT_QUIET, '-', "No warnings"},
    {"table", OPT_TABLE, '-', "Format output as table"},
    {"reverse", OPT_REVERSE, '-', "Switch table columns"},
103 104
    {"salt", OPT_SALT, 's', "Use provided salt"},
    {"stdin", OPT_STDIN, '-', "Read passwords from stdin"},
105 106 107 108 109 110 111 112 113
# ifndef NO_MD5CRYPT_1
    {"apr1", OPT_APR1, '-', "MD5-based password algorithm, Apache variant"},
    {"1", OPT_1, '-', "MD5-based password algorithm"},
# endif
# ifndef OPENSSL_NO_DES
    {"crypt", OPT_CRYPT, '-', "Standard Unix password algorithm (default)"},
# endif
    {NULL}
};
114

115
int passwd_main(int argc, char **argv)
116
{
117 118 119 120
    BIO *in = NULL;
    char *infile = NULL, *salt = NULL, *passwd = NULL, **passwds = NULL;
    char *salt_malloc = NULL, *passwd_malloc = NULL, *prog;
    OPTION_CHOICE o;
R
Richard Levitte 已提交
121 122 123 124
    int in_stdin = 0, pw_source_defined = 0;
#ifndef OPENSSL_NO_UI
    int in_noverify = 0;
#endif
125
    int passed_salt = 0, quiet = 0, table = 0, reverse = 0;
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
    int ret = 1, usecrypt = 0, use1 = 0, useapr1 = 0;
    size_t passwd_malloc_size = 0, pw_maxlen = 256;

    prog = opt_init(argc, argv, passwd_options);
    while ((o = opt_next()) != OPT_EOF) {
        switch (o) {
        case OPT_EOF:
        case OPT_ERR:
 opthelp:
            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
            goto end;
        case OPT_HELP:
            opt_help(passwd_options);
            ret = 0;
            goto end;
        case OPT_IN:
            if (pw_source_defined)
                goto opthelp;
            infile = opt_arg();
            pw_source_defined = 1;
            break;
        case OPT_NOVERIFY:
R
Richard Levitte 已提交
148
#ifndef OPENSSL_NO_UI
149
            in_noverify = 1;
R
Richard Levitte 已提交
150
#endif
151 152
            break;
        case OPT_QUIET:
153
            quiet = 1;
154 155
            break;
        case OPT_TABLE:
156
            table = 1;
157 158
            break;
        case OPT_REVERSE:
159
            reverse = 1;
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
            break;
        case OPT_1:
            use1 = 1;
            break;
        case OPT_APR1:
            useapr1 = 1;
            break;
        case OPT_CRYPT:
            usecrypt = 1;
            break;
        case OPT_SALT:
            passed_salt = 1;
            salt = opt_arg();
            break;
        case OPT_STDIN:
            if (pw_source_defined)
                goto opthelp;
            in_stdin = 1;
M
Matt Caswell 已提交
178
            pw_source_defined = 1;
179 180 181 182 183 184 185 186 187 188 189
            break;
        }
    }
    argc = opt_num_rest();
    argv = opt_rest();

    if (*argv) {
        if (pw_source_defined)
            goto opthelp;
        pw_source_defined = 1;
        passwds = argv;
190 191
    }

192 193
    if (!usecrypt && !use1 && !useapr1) {
        /* use default */
194
        usecrypt = 1;
195 196 197 198 199
    }
    if (usecrypt + use1 + useapr1 > 1) {
        /* conflict */
        goto opthelp;
    }
200 201 202

# ifdef OPENSSL_NO_DES
    if (usecrypt)
203
        goto opthelp;
204 205 206
# endif
# ifdef NO_MD5CRYPT_1
    if (use1 || useapr1)
207
        goto opthelp;
208 209
# endif

210
    if (infile != NULL && in_stdin) {
211 212
        BIO_printf(bio_err, "%s: Can't combine -in and -stdin\n", prog);
        goto end;
213 214
    }

215 216 217 218 219 220 221 222 223
    if (infile != NULL || in_stdin) {
        /*
         * If in_stdin is true, we know that infile is NULL, and that
         * bio_open_default() will give us back an alias for stdin.
         */
        in = bio_open_default(infile, 'r', FORMAT_TEXT);
        if (in == NULL)
            goto end;
    }
224 225 226 227 228 229 230 231 232 233 234

    if (usecrypt)
        pw_maxlen = 8;
    else if (use1 || useapr1)
        pw_maxlen = 256;        /* arbitrary limit, should be enough for most
                                 * passwords */

    if (passwds == NULL) {
        /* no passwords on the command line */

        passwd_malloc_size = pw_maxlen + 2;
R
Rich Salz 已提交
235 236 237
        /* longer than necessary so that we can warn about truncation */
        passwd = passwd_malloc =
            app_malloc(passwd_malloc_size, "password buffer");
238 239 240
    }

    if ((in == NULL) && (passwds == NULL)) {
R
Richard Levitte 已提交
241 242 243 244
        if (1) {
#ifndef OPENSSL_NO_UI
            /* build a null-terminated list */
            static char *passwds_static[2] = { NULL, NULL };
245

R
Richard Levitte 已提交
246 247 248 249 250 251 252 253 254 255 256 257
            passwds = passwds_static;
            if (in == NULL)
                if (EVP_read_pw_string
                    (passwd_malloc, passwd_malloc_size, "Password: ",
                     !(passed_salt || in_noverify)) != 0)
                    goto end;
            passwds[0] = passwd_malloc;
        } else {
#endif
            BIO_printf(bio_err, "password required\n");
            goto end;
        }
258 259
    }

R
Richard Levitte 已提交
260

261 262 263 264 265 266
    if (in == NULL) {
        assert(passwds != NULL);
        assert(*passwds != NULL);

        do {                    /* loop over list of passwords */
            passwd = *passwds++;
267
            if (!do_passwd(passed_salt, &salt, &salt_malloc, passwd, bio_out,
268 269
                           quiet, table, reverse, pw_maxlen, usecrypt, use1,
                           useapr1))
270
                goto end;
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
        }
        while (*passwds != NULL);
    } else
        /* in != NULL */
    {
        int done;

        assert(passwd != NULL);
        do {
            int r = BIO_gets(in, passwd, pw_maxlen + 1);
            if (r > 0) {
                char *c = (strchr(passwd, '\n'));
                if (c != NULL)
                    *c = 0;     /* truncate at newline */
                else {
                    /* ignore rest of line */
                    char trash[BUFSIZ];
                    do
                        r = BIO_gets(in, trash, sizeof trash);
                    while ((r > 0) && (!strchr(trash, '\n')));
                }

293 294 295 296
                if (!do_passwd
                    (passed_salt, &salt, &salt_malloc, passwd, bio_out, quiet,
                     table, reverse, pw_maxlen, usecrypt, use1, useapr1))
                    goto end;
297 298 299 300 301 302 303
            }
            done = (r <= 0);
        }
        while (!done);
    }
    ret = 0;

304
 end:
305
    ERR_print_errors(bio_err);
R
Rich Salz 已提交
306 307
    OPENSSL_free(salt_malloc);
    OPENSSL_free(passwd_malloc);
R
Rich Salz 已提交
308
    BIO_free(in);
309
    return (ret);
310 311 312 313 314 315 316 317 318 319 320
}

# ifndef NO_MD5CRYPT_1
/*
 * MD5-based password algorithm (should probably be available as a library
 * function; then the static buffer would not be acceptable). For magic
 * string "1", this should be compatible to the MD5-based BSD password
 * algorithm. For 'magic' string "apr1", this is compatible to the MD5-based
 * Apache password algorithm. (Apparently, the Apache password algorithm is
 * identical except that the 'magic' string was changed -- the laziest
 * application of the NIH principle I've ever encountered.)
321 322
 */
static char *md5crypt(const char *passwd, const char *magic, const char *salt)
323 324 325 326 327 328 329
{
    /* "$apr1$..salt..$.......md5hash..........\0" */
    static char out_buf[6 + 9 + 24 + 2];
    unsigned char buf[MD5_DIGEST_LENGTH];
    char *salt_out;
    int n;
    unsigned int i;
330
    EVP_MD_CTX *md, *md2;
331 332 333 334 335 336
    size_t passwd_len, salt_len;

    passwd_len = strlen(passwd);
    out_buf[0] = '$';
    out_buf[1] = 0;
    assert(strlen(magic) <= 4); /* "1" or "apr1" */
R
Rich Salz 已提交
337 338 339
    OPENSSL_strlcat(out_buf, magic, sizeof out_buf);
    OPENSSL_strlcat(out_buf, "$", sizeof out_buf);
    OPENSSL_strlcat(out_buf, salt, sizeof out_buf);
340 341 342 343 344
    assert(strlen(out_buf) <= 6 + 8); /* "$apr1$..salt.." */
    salt_out = out_buf + 2 + strlen(magic);
    salt_len = strlen(salt_out);
    assert(salt_len <= 8);

345
    md = EVP_MD_CTX_new();
346 347 348 349 350 351 352 353 354
    if (md == NULL)
        return NULL;
    EVP_DigestInit_ex(md, EVP_md5(), NULL);
    EVP_DigestUpdate(md, passwd, passwd_len);
    EVP_DigestUpdate(md, "$", 1);
    EVP_DigestUpdate(md, magic, strlen(magic));
    EVP_DigestUpdate(md, "$", 1);
    EVP_DigestUpdate(md, salt_out, salt_len);

355
    md2 = EVP_MD_CTX_new();
356 357 358 359 360 361 362
    if (md2 == NULL)
        return NULL;
    EVP_DigestInit_ex(md2, EVP_md5(), NULL);
    EVP_DigestUpdate(md2, passwd, passwd_len);
    EVP_DigestUpdate(md2, salt_out, salt_len);
    EVP_DigestUpdate(md2, passwd, passwd_len);
    EVP_DigestFinal_ex(md2, buf, NULL);
363 364

    for (i = passwd_len; i > sizeof buf; i -= sizeof buf)
365 366
        EVP_DigestUpdate(md, buf, sizeof buf);
    EVP_DigestUpdate(md, buf, i);
367 368 369

    n = passwd_len;
    while (n) {
370
        EVP_DigestUpdate(md, (n & 1) ? "\0" : passwd, 1);
371 372
        n >>= 1;
    }
373
    EVP_DigestFinal_ex(md, buf, NULL);
374 375

    for (i = 0; i < 1000; i++) {
376 377
        EVP_DigestInit_ex(md2, EVP_md5(), NULL);
        EVP_DigestUpdate(md2, (i & 1) ? (unsigned const char *)passwd : buf,
378 379
                         (i & 1) ? passwd_len : sizeof buf);
        if (i % 3)
380
            EVP_DigestUpdate(md2, salt_out, salt_len);
381
        if (i % 7)
382 383
            EVP_DigestUpdate(md2, passwd, passwd_len);
        EVP_DigestUpdate(md2, (i & 1) ? buf : (unsigned const char *)passwd,
384
                         (i & 1) ? sizeof buf : passwd_len);
385
        EVP_DigestFinal_ex(md2, buf, NULL);
386
    }
387 388
    EVP_MD_CTX_free(md2);
    EVP_MD_CTX_free(md);
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430

    {
        /* transform buf into output string */

        unsigned char buf_perm[sizeof buf];
        int dest, source;
        char *output;

        /* silly output permutation */
        for (dest = 0, source = 0; dest < 14;
             dest++, source = (source + 6) % 17)
            buf_perm[dest] = buf[source];
        buf_perm[14] = buf[5];
        buf_perm[15] = buf[11];
#  ifndef PEDANTIC              /* Unfortunately, this generates a "no
                                 * effect" warning */
        assert(16 == sizeof buf_perm);
#  endif

        output = salt_out + salt_len;
        assert(output == out_buf + strlen(out_buf));

        *output++ = '$';

        for (i = 0; i < 15; i += 3) {
            *output++ = cov_2char[buf_perm[i + 2] & 0x3f];
            *output++ = cov_2char[((buf_perm[i + 1] & 0xf) << 2) |
                                  (buf_perm[i + 2] >> 6)];
            *output++ = cov_2char[((buf_perm[i] & 3) << 4) |
                                  (buf_perm[i + 1] >> 4)];
            *output++ = cov_2char[buf_perm[i] >> 2];
        }
        assert(i == 15);
        *output++ = cov_2char[buf_perm[i] & 0x3f];
        *output++ = cov_2char[buf_perm[i] >> 6];
        *output = 0;
        assert(strlen(out_buf) < sizeof(out_buf));
    }

    return out_buf;
}
# endif
431 432

static int do_passwd(int passed_salt, char **salt_p, char **salt_malloc_p,
433 434 435 436 437 438 439 440 441 442 443 444 445 446
                     char *passwd, BIO *out, int quiet, int table,
                     int reverse, size_t pw_maxlen, int usecrypt, int use1,
                     int useapr1)
{
    char *hash = NULL;

    assert(salt_p != NULL);
    assert(salt_malloc_p != NULL);

    /* first make sure we have a salt */
    if (!passed_salt) {
# ifndef OPENSSL_NO_DES
        if (usecrypt) {
            if (*salt_malloc_p == NULL) {
R
Rich Salz 已提交
447
                *salt_p = *salt_malloc_p = app_malloc(3, "salt buffer");
448
            }
M
Matt Caswell 已提交
449
            if (RAND_bytes((unsigned char *)*salt_p, 2) <= 0)
450
                goto end;
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
            (*salt_p)[0] = cov_2char[(*salt_p)[0] & 0x3f]; /* 6 bits */
            (*salt_p)[1] = cov_2char[(*salt_p)[1] & 0x3f]; /* 6 bits */
            (*salt_p)[2] = 0;
#  ifdef CHARSET_EBCDIC
            ascii2ebcdic(*salt_p, *salt_p, 2); /* des_crypt will convert back
                                                * to ASCII */
#  endif
        }
# endif                         /* !OPENSSL_NO_DES */

# ifndef NO_MD5CRYPT_1
        if (use1 || useapr1) {
            int i;

            if (*salt_malloc_p == NULL) {
R
Rich Salz 已提交
466
                *salt_p = *salt_malloc_p = app_malloc(9, "salt buffer");
467
            }
M
Matt Caswell 已提交
468
            if (RAND_bytes((unsigned char *)*salt_p, 8) <= 0)
469
                goto end;
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510

            for (i = 0; i < 8; i++)
                (*salt_p)[i] = cov_2char[(*salt_p)[i] & 0x3f]; /* 6 bits */
            (*salt_p)[8] = 0;
        }
# endif                         /* !NO_MD5CRYPT_1 */
    }

    assert(*salt_p != NULL);

    /* truncate password if necessary */
    if ((strlen(passwd) > pw_maxlen)) {
        if (!quiet)
            /*
             * XXX: really we should know how to print a size_t, not cast it
             */
            BIO_printf(bio_err,
                       "Warning: truncating password to %u characters\n",
                       (unsigned)pw_maxlen);
        passwd[pw_maxlen] = 0;
    }
    assert(strlen(passwd) <= pw_maxlen);

    /* now compute password hash */
# ifndef OPENSSL_NO_DES
    if (usecrypt)
        hash = DES_crypt(passwd, *salt_p);
# endif
# ifndef NO_MD5CRYPT_1
    if (use1 || useapr1)
        hash = md5crypt(passwd, (use1 ? "1" : "apr1"), *salt_p);
# endif
    assert(hash != NULL);

    if (table && !reverse)
        BIO_printf(out, "%s\t%s\n", passwd, hash);
    else if (table && reverse)
        BIO_printf(out, "%s\t%s\n", hash, passwd);
    else
        BIO_printf(out, "%s\n", hash);
    return 0;
511 512 513

 end:
    return 1;
514
}
B
Bodo Möller 已提交
515
#else
516

517
int passwd_main(int argc, char **argv)
518
{
R
Rich Salz 已提交
519 520
    BIO_printf(bio_err, "Program not available.\n");
    return (1);
521
}
B
Bodo Möller 已提交
522
#endif