X-Git-Url: https://git.openssl.org/gitweb/?a=blobdiff_plain;f=apps%2Fdgst.c;h=90aaf982ae019c5facbcf5fba54843914c5445b7;hb=576bcdb5bdc1311064a108098eedc4a0723615ba;hp=1e3a72ccb46314e12df66dc1e5ca0ebc58d3de42;hpb=d175e8a6c23ca212bf57ff78fdbca6942f3e0ef7;p=openssl.git diff --git a/apps/dgst.c b/apps/dgst.c index 1e3a72ccb4..90aaf982ae 100644 --- a/apps/dgst.c +++ b/apps/dgst.c @@ -1,64 +1,17 @@ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. +/* + * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * 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 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 acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html */ #include #include #include #include "apps.h" +#include "progs.h" #include #include #include @@ -66,6 +19,9 @@ #include #include #include +#include + +DEFINE_STACK_OF_STRING() #undef BUFSIZE #define BUFSIZE 1024*8 @@ -73,49 +29,65 @@ int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, EVP_PKEY *key, unsigned char *sigin, int siglen, const char *sig_name, const char *md_name, - const char *file, BIO *bmd); + const char *file); +static void show_digests(const OBJ_NAME *name, void *bio_); + +struct doall_dgst_digests { + BIO *bio; + int n; +}; typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, - OPT_C, OPT_R, OPT_RAND, OPT_OUT, OPT_SIGN, OPT_PASSIN, OPT_VERIFY, + OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, OPT_LIST, + OPT_C, OPT_R, OPT_OUT, OPT_SIGN, OPT_PASSIN, OPT_VERIFY, OPT_PRVERIFY, OPT_SIGNATURE, OPT_KEYFORM, OPT_ENGINE, OPT_ENGINE_IMPL, OPT_HEX, OPT_BINARY, OPT_DEBUG, OPT_FIPS_FINGERPRINT, - OPT_NON_FIPS_ALLOW, OPT_HMAC, OPT_MAC, OPT_SIGOPT, OPT_MACOPT, - OPT_DIGEST + OPT_HMAC, OPT_MAC, OPT_SIGOPT, OPT_MACOPT, + OPT_DIGEST, + OPT_R_ENUM, OPT_PROV_ENUM } OPTION_CHOICE; -OPTIONS dgst_options[] = { +const OPTIONS dgst_options[] = { {OPT_HELP_STR, 1, '-', "Usage: %s [options] [file...]\n"}, - {OPT_HELP_STR, 1, '-', - " file... files to digest (default is stdin)\n"}, + + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, + {"list", OPT_LIST, '-', "List digests"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device"}, + {"engine_impl", OPT_ENGINE_IMPL, '-', + "Also use engine given by -engine for digest operations"}, +#endif + {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, + + OPT_SECTION("Output"), {"c", OPT_C, '-', "Print the digest with separating colons"}, {"r", OPT_R, '-', "Print the digest in coreutils format"}, - {"rand", OPT_RAND, 's'}, {"out", OPT_OUT, '>', "Output to filename rather than stdout"}, - {"passin", OPT_PASSIN, 's'}, - {"sign", OPT_SIGN, '<', "Sign digest using private key in file"}, - {"verify", OPT_VERIFY, '<', - "Verify a signature using public key in file"}, - {"prverify", OPT_PRVERIFY, '<', - "Verify a signature using private key in file"}, - {"signature", OPT_SIGNATURE, '<', "File with signature to verify"}, {"keyform", OPT_KEYFORM, 'f', "Key file format (PEM or ENGINE)"}, {"hex", OPT_HEX, '-', "Print as hex dump"}, {"binary", OPT_BINARY, '-', "Print in binary form"}, {"d", OPT_DEBUG, '-', "Print debug info"}, - {"debug", OPT_DEBUG, '-'}, - {"fips-fingerprint", OPT_FIPS_FINGERPRINT, '-'}, - {"non-fips-allow", OPT_NON_FIPS_ALLOW, '-'}, - {"hmac", OPT_HMAC, 's', "Create hashed MAC with key"}, - {"mac", OPT_MAC, 's', "Create MAC (not neccessarily HMAC)"}, + {"debug", OPT_DEBUG, '-', "Print debug info"}, + + OPT_SECTION("Signing"), + {"sign", OPT_SIGN, 's', "Sign digest using private key"}, + {"verify", OPT_VERIFY, 's', "Verify a signature using public key"}, + {"prverify", OPT_PRVERIFY, 's', "Verify a signature using private key"}, {"sigopt", OPT_SIGOPT, 's', "Signature parameter in n:v form"}, + {"signature", OPT_SIGNATURE, '<', "File with signature to verify"}, + {"hmac", OPT_HMAC, 's', "Create hashed MAC with key"}, + {"mac", OPT_MAC, 's', "Create MAC (not necessarily HMAC)"}, {"macopt", OPT_MACOPT, 's', "MAC algorithm parameters in n:v form or key"}, {"", OPT_DIGEST, '-', "Any supported digest"}, -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device"}, - {"engine_impl", OPT_ENGINE_IMPL, '-'}, -#endif + {"fips-fingerprint", OPT_FIPS_FINGERPRINT, '-', + "Compute HMAC with the key used in OpenSSL-FIPS fingerprint"}, + + OPT_R_OPTIONS, + OPT_PROV_OPTIONS, + + OPT_PARAMETERS(), + {"file", 0, 0, "Files to digest (optional; default is stdin)"}, {NULL} }; @@ -130,13 +102,14 @@ int dgst_main(int argc, char **argv) char *passinarg = NULL, *passin = NULL; const EVP_MD *md = NULL, *m; const char *outfile = NULL, *keyfile = NULL, *prog = NULL; - const char *sigfile = NULL, *randfile = NULL; + const char *sigfile = NULL; + const char *md_name = NULL; OPTION_CHOICE o; int separator = 0, debug = 0, keyform = FORMAT_PEM, siglen = 0; - int i, ret = 1, out_bin = -1, want_pub = 0, do_verify = - 0, non_fips_allow = 0; + int i, ret = 1, out_bin = -1, want_pub = 0, do_verify = 0; unsigned char *buf = NULL, *sigbuf = NULL; int engine_impl = 0; + struct doall_dgst_digests dec; prog = opt_progname(argv[0]); buf = app_malloc(BUFSIZE, "I/O buffer"); @@ -154,14 +127,24 @@ int dgst_main(int argc, char **argv) opt_help(dgst_options); ret = 0; goto end; + case OPT_LIST: + BIO_printf(bio_out, "Supported digests:\n"); + dec.bio = bio_out; + dec.n = 0; + OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH, + show_digests, &dec); + BIO_printf(bio_out, "\n"); + ret = 0; + goto end; case OPT_C: separator = 1; break; case OPT_R: separator = 2; break; - case OPT_RAND: - randfile = opt_arg(); + case OPT_R_CASES: + if (!opt_rand(o)) + goto end; break; case OPT_OUT: outfile = opt_arg(); @@ -205,9 +188,6 @@ int dgst_main(int argc, char **argv) case OPT_FIPS_FINGERPRINT: hmac_key = "etaonrishdlcupfm"; break; - case OPT_NON_FIPS_ALLOW: - non_fips_allow = 1; - break; case OPT_HMAC: hmac_key = opt_arg(); break; @@ -231,15 +211,20 @@ int dgst_main(int argc, char **argv) goto opthelp; md = m; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } argc = opt_num_rest(); argv = opt_rest(); - - if (!app_load_modules(NULL)) + if (keyfile != NULL && argc > 1) { + BIO_printf(bio_err, "%s: Can only sign or verify one file.\n", prog); goto end; + } - if (do_verify && !sigfile) { + if (do_verify && sigfile == NULL) { BIO_printf(bio_err, "No signature to verify: use the -signature option\n"); goto end; @@ -266,43 +251,51 @@ int dgst_main(int argc, char **argv) } if (out_bin == -1) { - if (keyfile) + if (keyfile != NULL) out_bin = 1; else out_bin = 0; } - if (randfile) - app_RAND_load_file(randfile, 0); - out = bio_open_default(outfile, 'w', out_bin ? FORMAT_BINARY : FORMAT_TEXT); if (out == NULL) goto end; - if ((! !mac_name + ! !keyfile + ! !hmac_key) > 1) { + if ((!(mac_name == NULL) + !(keyfile == NULL) + !(hmac_key == NULL)) > 1) { BIO_printf(bio_err, "MAC and Signing key cannot both be specified\n"); goto end; } - if (keyfile) { + if (keyfile != NULL) { + int type; + if (want_pub) sigkey = load_pubkey(keyfile, keyform, 0, NULL, e, "key file"); else sigkey = load_key(keyfile, keyform, 0, passin, e, "key file"); - if (!sigkey) { + if (sigkey == NULL) { /* * load_[pub]key() has already printed an appropriate message */ goto end; } + type = EVP_PKEY_id(sigkey); + if (type == EVP_PKEY_ED25519 || type == EVP_PKEY_ED448) { + /* + * We implement PureEdDSA for these which doesn't have a separate + * digest, and only supports one shot. + */ + BIO_printf(bio_err, "Key type not supported for this operation\n"); + goto end; + } } - if (mac_name) { + if (mac_name != NULL) { EVP_PKEY_CTX *mac_ctx = NULL; int r = 0; if (!init_gen_str(&mac_ctx, mac_name, impl, 0)) goto mac_end; - if (macopts) { + if (macopts != NULL) { char *macopt; for (i = 0; i < sk_OPENSSL_STRING_num(macopts); i++) { macopt = sk_OPENSSL_STRING_value(macopts, i); @@ -326,20 +319,14 @@ int dgst_main(int argc, char **argv) goto end; } - if (non_fips_allow) { - EVP_MD_CTX *md_ctx; - BIO_get_md_ctx(bmd, &md_ctx); - EVP_MD_CTX_set_flags(md_ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); - } - - if (hmac_key) { - sigkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, impl, - (unsigned char *)hmac_key, -1); - if (!sigkey) + if (hmac_key != NULL) { + sigkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, impl, + (unsigned char *)hmac_key, -1); + if (sigkey == NULL) goto end; } - if (sigkey) { + if (sigkey != NULL) { EVP_MD_CTX *mctx = NULL; EVP_PKEY_CTX *pctx = NULL; int r; @@ -357,7 +344,7 @@ int dgst_main(int argc, char **argv) ERR_print_errors(bio_err); goto end; } - if (sigopts) { + if (sigopts != NULL) { char *sigopt; for (i = 0; i < sk_OPENSSL_STRING_num(sigopts); i++) { sigopt = sk_OPENSSL_STRING_value(sigopts, i); @@ -378,7 +365,7 @@ int dgst_main(int argc, char **argv) goto end; } if (md == NULL) - md = EVP_md5(); + md = EVP_sha256(); if (!EVP_DigestInit_ex(mctx, md, impl)) { BIO_printf(bio_err, "Error setting digest\n"); ERR_print_errors(bio_err); @@ -386,9 +373,9 @@ int dgst_main(int argc, char **argv) } } - if (sigfile && sigkey) { + if (sigfile != NULL && sigkey != NULL) { BIO *sigbio = BIO_new_file(sigfile, "rb"); - if (!sigbio) { + if (sigbio == NULL) { BIO_printf(bio_err, "Error opening signature file %s\n", sigfile); ERR_print_errors(bio_err); goto end; @@ -410,23 +397,23 @@ int dgst_main(int argc, char **argv) BIO_get_md_ctx(bmd, &tctx); md = EVP_MD_CTX_md(tctx); } + if (md != NULL) + md_name = EVP_MD_name(md); if (argc == 0) { BIO_set_fp(in, stdin, BIO_NOCLOSE); ret = do_fp(out, buf, inp, separator, out_bin, sigkey, sigbuf, - siglen, NULL, NULL, "stdin", bmd); + siglen, NULL, md_name, "stdin"); } else { - const char *md_name = NULL, *sig_name = NULL; + const char *sig_name = NULL; if (!out_bin) { - if (sigkey) { + if (sigkey != NULL) { const EVP_PKEY_ASN1_METHOD *ameth; ameth = EVP_PKEY_get0_asn1(sigkey); if (ameth) EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, &sig_name, ameth); } - if (md) - md_name = EVP_MD_name(md); } ret = 0; for (i = 0; i < argc; i++) { @@ -435,9 +422,10 @@ int dgst_main(int argc, char **argv) perror(argv[i]); ret++; continue; - } else + } else { r = do_fp(out, buf, inp, separator, out_bin, sigkey, sigbuf, - siglen, sig_name, md_name, argv[i], bmd); + siglen, sig_name, md_name, argv[i]); + } if (r) ret = r; (void)BIO_reset(bmd); @@ -453,76 +441,163 @@ int dgst_main(int argc, char **argv) sk_OPENSSL_STRING_free(macopts); OPENSSL_free(sigbuf); BIO_free(bmd); - return (ret); + release_engine(e); + return ret; +} + +static void show_digests(const OBJ_NAME *name, void *arg) +{ + struct doall_dgst_digests *dec = (struct doall_dgst_digests *)arg; + const EVP_MD *md = NULL; + + /* Filter out signed digests (a.k.a signature algorithms) */ + if (strstr(name->name, "rsa") != NULL || strstr(name->name, "RSA") != NULL) + return; + + if (!islower((unsigned char)*name->name)) + return; + + /* Filter out message digests that we cannot use */ + md = EVP_get_digestbyname(name->name); + if (md == NULL) + return; + + BIO_printf(dec->bio, "-%-25s", name->name); + if (++dec->n == 3) { + BIO_printf(dec->bio, "\n"); + dec->n = 0; + } else { + BIO_printf(dec->bio, " "); + } +} + +/* + * The newline_escape_filename function performs newline escaping for any + * filename that contains a newline. This function also takes a pointer + * to backslash. The backslash pointer is a flag to indicating whether a newline + * is present in the filename. If a newline is present, the backslash flag is + * set and the output format will contain a backslash at the beginning of the + * digest output. This output format is to replicate the output format found + * in the '*sum' checksum programs. This aims to preserve backward + * compatibility. + */ +static const char *newline_escape_filename(const char *file, int * backslash) +{ + size_t i, e = 0, length = strlen(file), newline_count = 0, mem_len = 0; + char *file_cpy = NULL; + + for (i = 0; i < length; i++) + if (file[i] == '\n') + newline_count++; + + mem_len = length + newline_count + 1; + file_cpy = app_malloc(mem_len, file); + i = 0; + + while(e < length) { + const char c = file[e]; + if (c == '\n') { + file_cpy[i++] = '\\'; + file_cpy[i++] = 'n'; + *backslash = 1; + } else { + file_cpy[i++] = c; + } + e++; + } + file_cpy[i] = '\0'; + return (const char*)file_cpy; } + int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, EVP_PKEY *key, unsigned char *sigin, int siglen, const char *sig_name, const char *md_name, - const char *file, BIO *bmd) + const char *file) { - size_t len; - int i; + size_t len = BUFSIZE; + int i, backslash = 0, ret = 1; + unsigned char *sigbuf = NULL; - for (;;) { + while (BIO_pending(bp) || !BIO_eof(bp)) { i = BIO_read(bp, (char *)buf, BUFSIZE); if (i < 0) { BIO_printf(bio_err, "Read Error in %s\n", file); ERR_print_errors(bio_err); - return 1; + goto end; } if (i == 0) break; } - if (sigin) { + if (sigin != NULL) { EVP_MD_CTX *ctx; BIO_get_md_ctx(bp, &ctx); i = EVP_DigestVerifyFinal(ctx, sigin, (unsigned int)siglen); - if (i > 0) + if (i > 0) { BIO_printf(out, "Verified OK\n"); - else if (i == 0) { + } else if (i == 0) { BIO_printf(out, "Verification Failure\n"); - return 1; + goto end; } else { BIO_printf(bio_err, "Error Verifying Data\n"); ERR_print_errors(bio_err); - return 1; + goto end; } - return 0; + ret = 0; + goto end; } - if (key) { + if (key != NULL) { EVP_MD_CTX *ctx; + size_t tmplen; + BIO_get_md_ctx(bp, &ctx); - len = BUFSIZE; + if (!EVP_DigestSignFinal(ctx, NULL, &tmplen)) { + BIO_printf(bio_err, "Error Signing Data\n"); + ERR_print_errors(bio_err); + goto end; + } + if (tmplen > BUFSIZE) { + len = tmplen; + sigbuf = app_malloc(len, "Signature buffer"); + buf = sigbuf; + } if (!EVP_DigestSignFinal(ctx, buf, &len)) { BIO_printf(bio_err, "Error Signing Data\n"); ERR_print_errors(bio_err); - return 1; + goto end; } } else { len = BIO_gets(bp, (char *)buf, BUFSIZE); if ((int)len < 0) { ERR_print_errors(bio_err); - return 1; + goto end; } } - if (binout) + if (binout) { BIO_write(out, buf, len); - else if (sep == 2) { + } else if (sep == 2) { + file = newline_escape_filename(file, &backslash); + + if (backslash == 1) + BIO_puts(out, "\\"); + for (i = 0; i < (int)len; i++) BIO_printf(out, "%02x", buf[i]); + BIO_printf(out, " *%s\n", file); + OPENSSL_free((char *)file); } else { - if (sig_name) { + if (sig_name != NULL) { BIO_puts(out, sig_name); - if (md_name) + if (md_name != NULL) BIO_printf(out, "-%s", md_name); BIO_printf(out, "(%s)= ", file); - } else if (md_name) + } else if (md_name != NULL) { BIO_printf(out, "%s(%s)= ", md_name, file); - else + } else { BIO_printf(out, "(%s)= ", file); + } for (i = 0; i < (int)len; i++) { if (sep && (i != 0)) BIO_printf(out, ":"); @@ -530,5 +605,11 @@ int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, } BIO_printf(out, "\n"); } - return 0; + + ret = 0; + end: + if (sigbuf != NULL) + OPENSSL_clear_free(sigbuf, len); + + return ret; }