diff options
author | robot-piglet <robot-piglet@yandex-team.com> | 2023-09-06 12:31:14 +0300 |
---|---|---|
committer | robot-piglet <robot-piglet@yandex-team.com> | 2023-09-06 12:59:52 +0300 |
commit | 04a19cc6b675d2380241eaa4b6e584a07bbd4280 (patch) | |
tree | 072700370672dc35fc987c10419e5ab34f4ca7fd /contrib/libs/openssl/apps/dgst.c | |
parent | 3a349a1a0cd42df29e4c2b2c950a8bd1d14345e3 (diff) | |
download | ydb-04a19cc6b675d2380241eaa4b6e584a07bbd4280.tar.gz |
Intermediate changes
Diffstat (limited to 'contrib/libs/openssl/apps/dgst.c')
-rw-r--r-- | contrib/libs/openssl/apps/dgst.c | 596 |
1 files changed, 596 insertions, 0 deletions
diff --git a/contrib/libs/openssl/apps/dgst.c b/contrib/libs/openssl/apps/dgst.c new file mode 100644 index 0000000000..f9b184be4c --- /dev/null +++ b/contrib/libs/openssl/apps/dgst.c @@ -0,0 +1,596 @@ +/* + * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (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 <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "apps.h" +#include "progs.h" +#include <openssl/bio.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/objects.h> +#include <openssl/x509.h> +#include <openssl/pem.h> +#include <openssl/hmac.h> +#include <ctype.h> + +#undef BUFSIZE +#define BUFSIZE 1024*8 + +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); +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_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_HMAC, OPT_MAC, OPT_SIGOPT, OPT_MACOPT, + OPT_DIGEST, + OPT_R_ENUM +} OPTION_CHOICE; + +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"}, + {"help", OPT_HELP, '-', "Display this summary"}, + {"list", OPT_LIST, '-', "List digests"}, + {"c", OPT_C, '-', "Print the digest with separating colons"}, + {"r", OPT_R, '-', "Print the digest in coreutils format"}, + {"out", OPT_OUT, '>', "Output to filename rather than stdout"}, + {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, + {"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"}, + {"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, '-', "Print debug info"}, + {"fips-fingerprint", OPT_FIPS_FINGERPRINT, '-', + "Compute HMAC with the key used in OpenSSL-FIPS fingerprint"}, + {"hmac", OPT_HMAC, 's', "Create hashed MAC with key"}, + {"mac", OPT_MAC, 's', "Create MAC (not necessarily HMAC)"}, + {"sigopt", OPT_SIGOPT, 's', "Signature parameter in n:v form"}, + {"macopt", OPT_MACOPT, 's', "MAC algorithm parameters in n:v form or key"}, + {"", OPT_DIGEST, '-', "Any supported digest"}, + OPT_R_OPTIONS, +#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 + {NULL} +}; + +int dgst_main(int argc, char **argv) +{ + BIO *in = NULL, *inp, *bmd = NULL, *out = NULL; + ENGINE *e = NULL, *impl = NULL; + EVP_PKEY *sigkey = NULL; + STACK_OF(OPENSSL_STRING) *sigopts = NULL, *macopts = NULL; + char *hmac_key = NULL; + char *mac_name = NULL; + char *passinarg = NULL, *passin = NULL; + const EVP_MD *md = NULL, *m; + const char *outfile = NULL, *keyfile = NULL, *prog = NULL; + const char *sigfile = 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; + 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"); + md = EVP_get_digestbyname(prog); + + prog = opt_init(argc, argv, dgst_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(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_R_CASES: + if (!opt_rand(o)) + goto end; + break; + case OPT_OUT: + outfile = opt_arg(); + break; + case OPT_SIGN: + keyfile = opt_arg(); + break; + case OPT_PASSIN: + passinarg = opt_arg(); + break; + case OPT_VERIFY: + keyfile = opt_arg(); + want_pub = do_verify = 1; + break; + case OPT_PRVERIFY: + keyfile = opt_arg(); + do_verify = 1; + break; + case OPT_SIGNATURE: + sigfile = opt_arg(); + break; + case OPT_KEYFORM: + if (!opt_format(opt_arg(), OPT_FMT_ANY, &keyform)) + goto opthelp; + break; + case OPT_ENGINE: + e = setup_engine(opt_arg(), 0); + break; + case OPT_ENGINE_IMPL: + engine_impl = 1; + break; + case OPT_HEX: + out_bin = 0; + break; + case OPT_BINARY: + out_bin = 1; + break; + case OPT_DEBUG: + debug = 1; + break; + case OPT_FIPS_FINGERPRINT: + hmac_key = "etaonrishdlcupfm"; + break; + case OPT_HMAC: + hmac_key = opt_arg(); + break; + case OPT_MAC: + mac_name = opt_arg(); + break; + case OPT_SIGOPT: + if (!sigopts) + sigopts = sk_OPENSSL_STRING_new_null(); + if (!sigopts || !sk_OPENSSL_STRING_push(sigopts, opt_arg())) + goto opthelp; + break; + case OPT_MACOPT: + if (!macopts) + macopts = sk_OPENSSL_STRING_new_null(); + if (!macopts || !sk_OPENSSL_STRING_push(macopts, opt_arg())) + goto opthelp; + break; + case OPT_DIGEST: + if (!opt_md(opt_unknown(), &m)) + goto opthelp; + md = m; + break; + } + } + argc = opt_num_rest(); + argv = opt_rest(); + 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 == NULL) { + BIO_printf(bio_err, + "No signature to verify: use the -signature option\n"); + goto end; + } + if (engine_impl) + impl = e; + + in = BIO_new(BIO_s_file()); + bmd = BIO_new(BIO_f_md()); + if ((in == NULL) || (bmd == NULL)) { + ERR_print_errors(bio_err); + goto end; + } + + if (debug) { + BIO_set_callback(in, BIO_debug_callback); + /* needed for windows 3.1 */ + BIO_set_callback_arg(in, (char *)bio_err); + } + + if (!app_passwd(passinarg, NULL, &passin, NULL)) { + BIO_printf(bio_err, "Error getting password\n"); + goto end; + } + + if (out_bin == -1) { + if (keyfile != NULL) + out_bin = 1; + else + out_bin = 0; + } + + out = bio_open_default(outfile, 'w', out_bin ? FORMAT_BINARY : FORMAT_TEXT); + if (out == NULL) + goto end; + + 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 != 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 == 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 != 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 != NULL) { + char *macopt; + for (i = 0; i < sk_OPENSSL_STRING_num(macopts); i++) { + macopt = sk_OPENSSL_STRING_value(macopts, i); + if (pkey_ctrl_string(mac_ctx, macopt) <= 0) { + BIO_printf(bio_err, + "MAC parameter error \"%s\"\n", macopt); + ERR_print_errors(bio_err); + goto mac_end; + } + } + } + if (EVP_PKEY_keygen(mac_ctx, &sigkey) <= 0) { + BIO_puts(bio_err, "Error generating key\n"); + ERR_print_errors(bio_err); + goto mac_end; + } + r = 1; + mac_end: + EVP_PKEY_CTX_free(mac_ctx); + if (r == 0) + goto end; + } + + 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 != NULL) { + EVP_MD_CTX *mctx = NULL; + EVP_PKEY_CTX *pctx = NULL; + int r; + if (BIO_get_md_ctx(bmd, &mctx) <= 0) { + BIO_printf(bio_err, "Error getting context\n"); + ERR_print_errors(bio_err); + goto end; + } + if (do_verify) + r = EVP_DigestVerifyInit(mctx, &pctx, md, impl, sigkey); + else + r = EVP_DigestSignInit(mctx, &pctx, md, impl, sigkey); + if (!r) { + BIO_printf(bio_err, "Error setting context\n"); + ERR_print_errors(bio_err); + goto end; + } + if (sigopts != NULL) { + char *sigopt; + for (i = 0; i < sk_OPENSSL_STRING_num(sigopts); i++) { + sigopt = sk_OPENSSL_STRING_value(sigopts, i); + if (pkey_ctrl_string(pctx, sigopt) <= 0) { + BIO_printf(bio_err, "parameter error \"%s\"\n", sigopt); + ERR_print_errors(bio_err); + goto end; + } + } + } + } + /* we use md as a filter, reading from 'in' */ + else { + EVP_MD_CTX *mctx = NULL; + if (BIO_get_md_ctx(bmd, &mctx) <= 0) { + BIO_printf(bio_err, "Error getting context\n"); + ERR_print_errors(bio_err); + goto end; + } + if (md == NULL) + md = EVP_sha256(); + if (!EVP_DigestInit_ex(mctx, md, impl)) { + BIO_printf(bio_err, "Error setting digest\n"); + ERR_print_errors(bio_err); + goto end; + } + } + + if (sigfile != NULL && sigkey != NULL) { + BIO *sigbio = BIO_new_file(sigfile, "rb"); + if (sigbio == NULL) { + BIO_printf(bio_err, "Error opening signature file %s\n", sigfile); + ERR_print_errors(bio_err); + goto end; + } + siglen = EVP_PKEY_size(sigkey); + sigbuf = app_malloc(siglen, "signature buffer"); + siglen = BIO_read(sigbio, sigbuf, siglen); + BIO_free(sigbio); + if (siglen <= 0) { + BIO_printf(bio_err, "Error reading signature file %s\n", sigfile); + ERR_print_errors(bio_err); + goto end; + } + } + inp = BIO_push(bmd, in); + + if (md == NULL) { + EVP_MD_CTX *tctx; + BIO_get_md_ctx(bmd, &tctx); + md = EVP_MD_CTX_md(tctx); + } + + 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"); + } else { + const char *md_name = NULL, *sig_name = NULL; + if (!out_bin) { + 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 != NULL) + md_name = EVP_MD_name(md); + } + ret = 0; + for (i = 0; i < argc; i++) { + int r; + if (BIO_read_filename(in, argv[i]) <= 0) { + perror(argv[i]); + ret++; + continue; + } else { + r = do_fp(out, buf, inp, separator, out_bin, sigkey, sigbuf, + siglen, sig_name, md_name, argv[i]); + } + if (r) + ret = r; + (void)BIO_reset(bmd); + } + } + end: + OPENSSL_clear_free(buf, BUFSIZE); + BIO_free(in); + OPENSSL_free(passin); + BIO_free_all(out); + EVP_PKEY_free(sigkey); + sk_OPENSSL_STRING_free(sigopts); + sk_OPENSSL_STRING_free(macopts); + OPENSSL_free(sigbuf); + BIO_free(bmd); + 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) +{ + size_t len = BUFSIZE; + int i, backslash = 0, ret = 1; + unsigned char *sigbuf = NULL; + + 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); + goto end; + } + if (i == 0) + break; + } + if (sigin != NULL) { + EVP_MD_CTX *ctx; + BIO_get_md_ctx(bp, &ctx); + i = EVP_DigestVerifyFinal(ctx, sigin, (unsigned int)siglen); + if (i > 0) { + BIO_printf(out, "Verified OK\n"); + } else if (i == 0) { + BIO_printf(out, "Verification Failure\n"); + goto end; + } else { + BIO_printf(bio_err, "Error Verifying Data\n"); + ERR_print_errors(bio_err); + goto end; + } + ret = 0; + goto end; + } + if (key != NULL) { + EVP_MD_CTX *ctx; + int pkey_len; + BIO_get_md_ctx(bp, &ctx); + pkey_len = EVP_PKEY_size(key); + if (pkey_len > BUFSIZE) { + len = pkey_len; + 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); + goto end; + } + } else { + len = BIO_gets(bp, (char *)buf, BUFSIZE); + if ((int)len < 0) { + ERR_print_errors(bio_err); + goto end; + } + } + + if (binout) { + BIO_write(out, buf, len); + } 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 != NULL) { + BIO_puts(out, sig_name); + if (md_name != NULL) + BIO_printf(out, "-%s", md_name); + BIO_printf(out, "(%s)= ", file); + } else if (md_name != NULL) { + BIO_printf(out, "%s(%s)= ", md_name, file); + } else { + BIO_printf(out, "(%s)= ", file); + } + for (i = 0; i < (int)len; i++) { + if (sep && (i != 0)) + BIO_printf(out, ":"); + BIO_printf(out, "%02x", buf[i]); + } + BIO_printf(out, "\n"); + } + + ret = 0; + end: + if (sigbuf != NULL) + OPENSSL_clear_free(sigbuf, len); + + return ret; +} |