1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci#include <stdio.h>
11e1051a39Sopenharmony_ci#include <string.h>
12e1051a39Sopenharmony_ci#include <stdlib.h>
13e1051a39Sopenharmony_ci#include "apps.h"
14e1051a39Sopenharmony_ci#include "progs.h"
15e1051a39Sopenharmony_ci#include <openssl/bio.h>
16e1051a39Sopenharmony_ci#include <openssl/err.h>
17e1051a39Sopenharmony_ci#include <openssl/evp.h>
18e1051a39Sopenharmony_ci#include <openssl/objects.h>
19e1051a39Sopenharmony_ci#include <openssl/x509.h>
20e1051a39Sopenharmony_ci#include <openssl/pem.h>
21e1051a39Sopenharmony_ci#include <openssl/hmac.h>
22e1051a39Sopenharmony_ci#include <ctype.h>
23e1051a39Sopenharmony_ci
24e1051a39Sopenharmony_ci#undef BUFSIZE
25e1051a39Sopenharmony_ci#define BUFSIZE 1024*8
26e1051a39Sopenharmony_ci
27e1051a39Sopenharmony_ciint do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, int xoflen,
28e1051a39Sopenharmony_ci          EVP_PKEY *key, unsigned char *sigin, int siglen,
29e1051a39Sopenharmony_ci          const char *sig_name, const char *md_name,
30e1051a39Sopenharmony_ci          const char *file);
31e1051a39Sopenharmony_cistatic void show_digests(const OBJ_NAME *name, void *bio_);
32e1051a39Sopenharmony_ci
33e1051a39Sopenharmony_cistruct doall_dgst_digests {
34e1051a39Sopenharmony_ci    BIO *bio;
35e1051a39Sopenharmony_ci    int n;
36e1051a39Sopenharmony_ci};
37e1051a39Sopenharmony_ci
38e1051a39Sopenharmony_citypedef enum OPTION_choice {
39e1051a39Sopenharmony_ci    OPT_COMMON,
40e1051a39Sopenharmony_ci    OPT_LIST,
41e1051a39Sopenharmony_ci    OPT_C, OPT_R, OPT_OUT, OPT_SIGN, OPT_PASSIN, OPT_VERIFY,
42e1051a39Sopenharmony_ci    OPT_PRVERIFY, OPT_SIGNATURE, OPT_KEYFORM, OPT_ENGINE, OPT_ENGINE_IMPL,
43e1051a39Sopenharmony_ci    OPT_HEX, OPT_BINARY, OPT_DEBUG, OPT_FIPS_FINGERPRINT,
44e1051a39Sopenharmony_ci    OPT_HMAC, OPT_MAC, OPT_SIGOPT, OPT_MACOPT, OPT_XOFLEN,
45e1051a39Sopenharmony_ci    OPT_DIGEST,
46e1051a39Sopenharmony_ci    OPT_R_ENUM, OPT_PROV_ENUM
47e1051a39Sopenharmony_ci} OPTION_CHOICE;
48e1051a39Sopenharmony_ci
49e1051a39Sopenharmony_ciconst OPTIONS dgst_options[] = {
50e1051a39Sopenharmony_ci    {OPT_HELP_STR, 1, '-', "Usage: %s [options] [file...]\n"},
51e1051a39Sopenharmony_ci
52e1051a39Sopenharmony_ci    OPT_SECTION("General"),
53e1051a39Sopenharmony_ci    {"help", OPT_HELP, '-', "Display this summary"},
54e1051a39Sopenharmony_ci    {"list", OPT_LIST, '-', "List digests"},
55e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_ENGINE
56e1051a39Sopenharmony_ci    {"engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device"},
57e1051a39Sopenharmony_ci    {"engine_impl", OPT_ENGINE_IMPL, '-',
58e1051a39Sopenharmony_ci     "Also use engine given by -engine for digest operations"},
59e1051a39Sopenharmony_ci#endif
60e1051a39Sopenharmony_ci    {"passin", OPT_PASSIN, 's', "Input file pass phrase source"},
61e1051a39Sopenharmony_ci
62e1051a39Sopenharmony_ci    OPT_SECTION("Output"),
63e1051a39Sopenharmony_ci    {"c", OPT_C, '-', "Print the digest with separating colons"},
64e1051a39Sopenharmony_ci    {"r", OPT_R, '-', "Print the digest in coreutils format"},
65e1051a39Sopenharmony_ci    {"out", OPT_OUT, '>', "Output to filename rather than stdout"},
66e1051a39Sopenharmony_ci    {"keyform", OPT_KEYFORM, 'f', "Key file format (ENGINE, other values ignored)"},
67e1051a39Sopenharmony_ci    {"hex", OPT_HEX, '-', "Print as hex dump"},
68e1051a39Sopenharmony_ci    {"binary", OPT_BINARY, '-', "Print in binary form"},
69e1051a39Sopenharmony_ci    {"xoflen", OPT_XOFLEN, 'p', "Output length for XOF algorithms. To obtain the maximum security strength set this to 32 (or greater) for SHAKE128, and 64 (or greater) for SHAKE256"},
70e1051a39Sopenharmony_ci    {"d", OPT_DEBUG, '-', "Print debug info"},
71e1051a39Sopenharmony_ci    {"debug", OPT_DEBUG, '-', "Print debug info"},
72e1051a39Sopenharmony_ci
73e1051a39Sopenharmony_ci    OPT_SECTION("Signing"),
74e1051a39Sopenharmony_ci    {"sign", OPT_SIGN, 's', "Sign digest using private key"},
75e1051a39Sopenharmony_ci    {"verify", OPT_VERIFY, 's', "Verify a signature using public key"},
76e1051a39Sopenharmony_ci    {"prverify", OPT_PRVERIFY, 's', "Verify a signature using private key"},
77e1051a39Sopenharmony_ci    {"sigopt", OPT_SIGOPT, 's', "Signature parameter in n:v form"},
78e1051a39Sopenharmony_ci    {"signature", OPT_SIGNATURE, '<', "File with signature to verify"},
79e1051a39Sopenharmony_ci    {"hmac", OPT_HMAC, 's', "Create hashed MAC with key"},
80e1051a39Sopenharmony_ci    {"mac", OPT_MAC, 's', "Create MAC (not necessarily HMAC)"},
81e1051a39Sopenharmony_ci    {"macopt", OPT_MACOPT, 's', "MAC algorithm parameters in n:v form or key"},
82e1051a39Sopenharmony_ci    {"", OPT_DIGEST, '-', "Any supported digest"},
83e1051a39Sopenharmony_ci    {"fips-fingerprint", OPT_FIPS_FINGERPRINT, '-',
84e1051a39Sopenharmony_ci     "Compute HMAC with the key used in OpenSSL-FIPS fingerprint"},
85e1051a39Sopenharmony_ci
86e1051a39Sopenharmony_ci    OPT_R_OPTIONS,
87e1051a39Sopenharmony_ci    OPT_PROV_OPTIONS,
88e1051a39Sopenharmony_ci
89e1051a39Sopenharmony_ci    OPT_PARAMETERS(),
90e1051a39Sopenharmony_ci    {"file", 0, 0, "Files to digest (optional; default is stdin)"},
91e1051a39Sopenharmony_ci    {NULL}
92e1051a39Sopenharmony_ci};
93e1051a39Sopenharmony_ci
94e1051a39Sopenharmony_ciint dgst_main(int argc, char **argv)
95e1051a39Sopenharmony_ci{
96e1051a39Sopenharmony_ci    BIO *in = NULL, *inp, *bmd = NULL, *out = NULL;
97e1051a39Sopenharmony_ci    ENGINE *e = NULL, *impl = NULL;
98e1051a39Sopenharmony_ci    EVP_PKEY *sigkey = NULL;
99e1051a39Sopenharmony_ci    STACK_OF(OPENSSL_STRING) *sigopts = NULL, *macopts = NULL;
100e1051a39Sopenharmony_ci    char *hmac_key = NULL;
101e1051a39Sopenharmony_ci    char *mac_name = NULL, *digestname = NULL;
102e1051a39Sopenharmony_ci    char *passinarg = NULL, *passin = NULL;
103e1051a39Sopenharmony_ci    EVP_MD *md = NULL;
104e1051a39Sopenharmony_ci    const char *outfile = NULL, *keyfile = NULL, *prog = NULL;
105e1051a39Sopenharmony_ci    const char *sigfile = NULL;
106e1051a39Sopenharmony_ci    const char *md_name = NULL;
107e1051a39Sopenharmony_ci    OPTION_CHOICE o;
108e1051a39Sopenharmony_ci    int separator = 0, debug = 0, keyform = FORMAT_UNDEF, siglen = 0;
109e1051a39Sopenharmony_ci    int i, ret = EXIT_FAILURE, out_bin = -1, want_pub = 0, do_verify = 0;
110e1051a39Sopenharmony_ci    int xoflen = 0;
111e1051a39Sopenharmony_ci    unsigned char *buf = NULL, *sigbuf = NULL;
112e1051a39Sopenharmony_ci    int engine_impl = 0;
113e1051a39Sopenharmony_ci    struct doall_dgst_digests dec;
114e1051a39Sopenharmony_ci
115e1051a39Sopenharmony_ci    buf = app_malloc(BUFSIZE, "I/O buffer");
116e1051a39Sopenharmony_ci    md = (EVP_MD *)EVP_get_digestbyname(argv[0]);
117e1051a39Sopenharmony_ci    if (md != NULL)
118e1051a39Sopenharmony_ci        digestname = argv[0];
119e1051a39Sopenharmony_ci
120e1051a39Sopenharmony_ci    prog = opt_init(argc, argv, dgst_options);
121e1051a39Sopenharmony_ci    while ((o = opt_next()) != OPT_EOF) {
122e1051a39Sopenharmony_ci        switch (o) {
123e1051a39Sopenharmony_ci        case OPT_EOF:
124e1051a39Sopenharmony_ci        case OPT_ERR:
125e1051a39Sopenharmony_ci opthelp:
126e1051a39Sopenharmony_ci            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
127e1051a39Sopenharmony_ci            goto end;
128e1051a39Sopenharmony_ci        case OPT_HELP:
129e1051a39Sopenharmony_ci            opt_help(dgst_options);
130e1051a39Sopenharmony_ci            ret = EXIT_SUCCESS;
131e1051a39Sopenharmony_ci            goto end;
132e1051a39Sopenharmony_ci        case OPT_LIST:
133e1051a39Sopenharmony_ci            BIO_printf(bio_out, "Supported digests:\n");
134e1051a39Sopenharmony_ci            dec.bio = bio_out;
135e1051a39Sopenharmony_ci            dec.n = 0;
136e1051a39Sopenharmony_ci            OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH,
137e1051a39Sopenharmony_ci                                   show_digests, &dec);
138e1051a39Sopenharmony_ci            BIO_printf(bio_out, "\n");
139e1051a39Sopenharmony_ci            ret = EXIT_SUCCESS;
140e1051a39Sopenharmony_ci            goto end;
141e1051a39Sopenharmony_ci        case OPT_C:
142e1051a39Sopenharmony_ci            separator = 1;
143e1051a39Sopenharmony_ci            break;
144e1051a39Sopenharmony_ci        case OPT_R:
145e1051a39Sopenharmony_ci            separator = 2;
146e1051a39Sopenharmony_ci            break;
147e1051a39Sopenharmony_ci        case OPT_R_CASES:
148e1051a39Sopenharmony_ci            if (!opt_rand(o))
149e1051a39Sopenharmony_ci                goto end;
150e1051a39Sopenharmony_ci            break;
151e1051a39Sopenharmony_ci        case OPT_OUT:
152e1051a39Sopenharmony_ci            outfile = opt_arg();
153e1051a39Sopenharmony_ci            break;
154e1051a39Sopenharmony_ci        case OPT_SIGN:
155e1051a39Sopenharmony_ci            keyfile = opt_arg();
156e1051a39Sopenharmony_ci            break;
157e1051a39Sopenharmony_ci        case OPT_PASSIN:
158e1051a39Sopenharmony_ci            passinarg = opt_arg();
159e1051a39Sopenharmony_ci            break;
160e1051a39Sopenharmony_ci        case OPT_VERIFY:
161e1051a39Sopenharmony_ci            keyfile = opt_arg();
162e1051a39Sopenharmony_ci            want_pub = do_verify = 1;
163e1051a39Sopenharmony_ci            break;
164e1051a39Sopenharmony_ci        case OPT_PRVERIFY:
165e1051a39Sopenharmony_ci            keyfile = opt_arg();
166e1051a39Sopenharmony_ci            do_verify = 1;
167e1051a39Sopenharmony_ci            break;
168e1051a39Sopenharmony_ci        case OPT_SIGNATURE:
169e1051a39Sopenharmony_ci            sigfile = opt_arg();
170e1051a39Sopenharmony_ci            break;
171e1051a39Sopenharmony_ci        case OPT_KEYFORM:
172e1051a39Sopenharmony_ci            if (!opt_format(opt_arg(), OPT_FMT_ANY, &keyform))
173e1051a39Sopenharmony_ci                goto opthelp;
174e1051a39Sopenharmony_ci            break;
175e1051a39Sopenharmony_ci        case OPT_ENGINE:
176e1051a39Sopenharmony_ci            e = setup_engine(opt_arg(), 0);
177e1051a39Sopenharmony_ci            break;
178e1051a39Sopenharmony_ci        case OPT_ENGINE_IMPL:
179e1051a39Sopenharmony_ci            engine_impl = 1;
180e1051a39Sopenharmony_ci            break;
181e1051a39Sopenharmony_ci        case OPT_HEX:
182e1051a39Sopenharmony_ci            out_bin = 0;
183e1051a39Sopenharmony_ci            break;
184e1051a39Sopenharmony_ci        case OPT_BINARY:
185e1051a39Sopenharmony_ci            out_bin = 1;
186e1051a39Sopenharmony_ci            break;
187e1051a39Sopenharmony_ci        case OPT_XOFLEN:
188e1051a39Sopenharmony_ci            xoflen = atoi(opt_arg());
189e1051a39Sopenharmony_ci            break;
190e1051a39Sopenharmony_ci        case OPT_DEBUG:
191e1051a39Sopenharmony_ci            debug = 1;
192e1051a39Sopenharmony_ci            break;
193e1051a39Sopenharmony_ci        case OPT_FIPS_FINGERPRINT:
194e1051a39Sopenharmony_ci            hmac_key = "etaonrishdlcupfm";
195e1051a39Sopenharmony_ci            break;
196e1051a39Sopenharmony_ci        case OPT_HMAC:
197e1051a39Sopenharmony_ci            hmac_key = opt_arg();
198e1051a39Sopenharmony_ci            break;
199e1051a39Sopenharmony_ci        case OPT_MAC:
200e1051a39Sopenharmony_ci            mac_name = opt_arg();
201e1051a39Sopenharmony_ci            break;
202e1051a39Sopenharmony_ci        case OPT_SIGOPT:
203e1051a39Sopenharmony_ci            if (!sigopts)
204e1051a39Sopenharmony_ci                sigopts = sk_OPENSSL_STRING_new_null();
205e1051a39Sopenharmony_ci            if (!sigopts || !sk_OPENSSL_STRING_push(sigopts, opt_arg()))
206e1051a39Sopenharmony_ci                goto opthelp;
207e1051a39Sopenharmony_ci            break;
208e1051a39Sopenharmony_ci        case OPT_MACOPT:
209e1051a39Sopenharmony_ci            if (!macopts)
210e1051a39Sopenharmony_ci                macopts = sk_OPENSSL_STRING_new_null();
211e1051a39Sopenharmony_ci            if (!macopts || !sk_OPENSSL_STRING_push(macopts, opt_arg()))
212e1051a39Sopenharmony_ci                goto opthelp;
213e1051a39Sopenharmony_ci            break;
214e1051a39Sopenharmony_ci        case OPT_DIGEST:
215e1051a39Sopenharmony_ci            digestname = opt_unknown();
216e1051a39Sopenharmony_ci            break;
217e1051a39Sopenharmony_ci        case OPT_PROV_CASES:
218e1051a39Sopenharmony_ci            if (!opt_provider(o))
219e1051a39Sopenharmony_ci                goto end;
220e1051a39Sopenharmony_ci            break;
221e1051a39Sopenharmony_ci        }
222e1051a39Sopenharmony_ci    }
223e1051a39Sopenharmony_ci
224e1051a39Sopenharmony_ci    /* Remaining args are files to digest. */
225e1051a39Sopenharmony_ci    argc = opt_num_rest();
226e1051a39Sopenharmony_ci    argv = opt_rest();
227e1051a39Sopenharmony_ci    if (keyfile != NULL && argc > 1) {
228e1051a39Sopenharmony_ci        BIO_printf(bio_err, "%s: Can only sign or verify one file.\n", prog);
229e1051a39Sopenharmony_ci        goto end;
230e1051a39Sopenharmony_ci    }
231e1051a39Sopenharmony_ci    if (!app_RAND_load())
232e1051a39Sopenharmony_ci        goto end;
233e1051a39Sopenharmony_ci
234e1051a39Sopenharmony_ci    if (digestname != NULL) {
235e1051a39Sopenharmony_ci        if (!opt_md(digestname, &md))
236e1051a39Sopenharmony_ci            goto opthelp;
237e1051a39Sopenharmony_ci    }
238e1051a39Sopenharmony_ci
239e1051a39Sopenharmony_ci    if (do_verify && sigfile == NULL) {
240e1051a39Sopenharmony_ci        BIO_printf(bio_err,
241e1051a39Sopenharmony_ci                   "No signature to verify: use the -signature option\n");
242e1051a39Sopenharmony_ci        goto end;
243e1051a39Sopenharmony_ci    }
244e1051a39Sopenharmony_ci    if (engine_impl)
245e1051a39Sopenharmony_ci        impl = e;
246e1051a39Sopenharmony_ci
247e1051a39Sopenharmony_ci    in = BIO_new(BIO_s_file());
248e1051a39Sopenharmony_ci    bmd = BIO_new(BIO_f_md());
249e1051a39Sopenharmony_ci    if (in == NULL || bmd == NULL)
250e1051a39Sopenharmony_ci        goto end;
251e1051a39Sopenharmony_ci
252e1051a39Sopenharmony_ci    if (debug) {
253e1051a39Sopenharmony_ci        BIO_set_callback_ex(in, BIO_debug_callback_ex);
254e1051a39Sopenharmony_ci        /* needed for windows 3.1 */
255e1051a39Sopenharmony_ci        BIO_set_callback_arg(in, (char *)bio_err);
256e1051a39Sopenharmony_ci    }
257e1051a39Sopenharmony_ci
258e1051a39Sopenharmony_ci    if (!app_passwd(passinarg, NULL, &passin, NULL)) {
259e1051a39Sopenharmony_ci        BIO_printf(bio_err, "Error getting password\n");
260e1051a39Sopenharmony_ci        goto end;
261e1051a39Sopenharmony_ci    }
262e1051a39Sopenharmony_ci
263e1051a39Sopenharmony_ci    if (out_bin == -1) {
264e1051a39Sopenharmony_ci        if (keyfile != NULL)
265e1051a39Sopenharmony_ci            out_bin = 1;
266e1051a39Sopenharmony_ci        else
267e1051a39Sopenharmony_ci            out_bin = 0;
268e1051a39Sopenharmony_ci    }
269e1051a39Sopenharmony_ci
270e1051a39Sopenharmony_ci    out = bio_open_default(outfile, 'w', out_bin ? FORMAT_BINARY : FORMAT_TEXT);
271e1051a39Sopenharmony_ci    if (out == NULL)
272e1051a39Sopenharmony_ci        goto end;
273e1051a39Sopenharmony_ci
274e1051a39Sopenharmony_ci    if ((!(mac_name == NULL) + !(keyfile == NULL) + !(hmac_key == NULL)) > 1) {
275e1051a39Sopenharmony_ci        BIO_printf(bio_err, "MAC and signing key cannot both be specified\n");
276e1051a39Sopenharmony_ci        goto end;
277e1051a39Sopenharmony_ci    }
278e1051a39Sopenharmony_ci
279e1051a39Sopenharmony_ci    if (keyfile != NULL) {
280e1051a39Sopenharmony_ci        int type;
281e1051a39Sopenharmony_ci
282e1051a39Sopenharmony_ci        if (want_pub)
283e1051a39Sopenharmony_ci            sigkey = load_pubkey(keyfile, keyform, 0, NULL, e, "public key");
284e1051a39Sopenharmony_ci        else
285e1051a39Sopenharmony_ci            sigkey = load_key(keyfile, keyform, 0, passin, e, "private key");
286e1051a39Sopenharmony_ci        if (sigkey == NULL) {
287e1051a39Sopenharmony_ci            /*
288e1051a39Sopenharmony_ci             * load_[pub]key() has already printed an appropriate message
289e1051a39Sopenharmony_ci             */
290e1051a39Sopenharmony_ci            goto end;
291e1051a39Sopenharmony_ci        }
292e1051a39Sopenharmony_ci        type = EVP_PKEY_get_id(sigkey);
293e1051a39Sopenharmony_ci        if (type == EVP_PKEY_ED25519 || type == EVP_PKEY_ED448) {
294e1051a39Sopenharmony_ci            /*
295e1051a39Sopenharmony_ci             * We implement PureEdDSA for these which doesn't have a separate
296e1051a39Sopenharmony_ci             * digest, and only supports one shot.
297e1051a39Sopenharmony_ci             */
298e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Key type not supported for this operation\n");
299e1051a39Sopenharmony_ci            goto end;
300e1051a39Sopenharmony_ci        }
301e1051a39Sopenharmony_ci    }
302e1051a39Sopenharmony_ci
303e1051a39Sopenharmony_ci    if (mac_name != NULL) {
304e1051a39Sopenharmony_ci        EVP_PKEY_CTX *mac_ctx = NULL;
305e1051a39Sopenharmony_ci
306e1051a39Sopenharmony_ci        if (!init_gen_str(&mac_ctx, mac_name, impl, 0, NULL, NULL))
307e1051a39Sopenharmony_ci            goto end;
308e1051a39Sopenharmony_ci        if (macopts != NULL) {
309e1051a39Sopenharmony_ci            for (i = 0; i < sk_OPENSSL_STRING_num(macopts); i++) {
310e1051a39Sopenharmony_ci                char *macopt = sk_OPENSSL_STRING_value(macopts, i);
311e1051a39Sopenharmony_ci
312e1051a39Sopenharmony_ci                if (pkey_ctrl_string(mac_ctx, macopt) <= 0) {
313e1051a39Sopenharmony_ci                    EVP_PKEY_CTX_free(mac_ctx);
314e1051a39Sopenharmony_ci                    BIO_printf(bio_err, "MAC parameter error \"%s\"\n", macopt);
315e1051a39Sopenharmony_ci                    goto end;
316e1051a39Sopenharmony_ci                }
317e1051a39Sopenharmony_ci            }
318e1051a39Sopenharmony_ci        }
319e1051a39Sopenharmony_ci
320e1051a39Sopenharmony_ci        sigkey = app_keygen(mac_ctx, mac_name, 0, 0 /* not verbose */);
321e1051a39Sopenharmony_ci        /* Verbose output would make external-tests gost-engine fail */
322e1051a39Sopenharmony_ci        EVP_PKEY_CTX_free(mac_ctx);
323e1051a39Sopenharmony_ci        if (sigkey == NULL)
324e1051a39Sopenharmony_ci            goto end;
325e1051a39Sopenharmony_ci    }
326e1051a39Sopenharmony_ci
327e1051a39Sopenharmony_ci    if (hmac_key != NULL) {
328e1051a39Sopenharmony_ci        if (md == NULL) {
329e1051a39Sopenharmony_ci            md = (EVP_MD *)EVP_sha256();
330e1051a39Sopenharmony_ci            digestname = SN_sha256;
331e1051a39Sopenharmony_ci        }
332e1051a39Sopenharmony_ci        sigkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, impl,
333e1051a39Sopenharmony_ci                                              (unsigned char *)hmac_key,
334e1051a39Sopenharmony_ci                                              strlen(hmac_key));
335e1051a39Sopenharmony_ci        if (sigkey == NULL)
336e1051a39Sopenharmony_ci            goto end;
337e1051a39Sopenharmony_ci    }
338e1051a39Sopenharmony_ci
339e1051a39Sopenharmony_ci    if (sigkey != NULL) {
340e1051a39Sopenharmony_ci        EVP_MD_CTX *mctx = NULL;
341e1051a39Sopenharmony_ci        EVP_PKEY_CTX *pctx = NULL;
342e1051a39Sopenharmony_ci        int res;
343e1051a39Sopenharmony_ci
344e1051a39Sopenharmony_ci        if (BIO_get_md_ctx(bmd, &mctx) <= 0) {
345e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Error getting context\n");
346e1051a39Sopenharmony_ci            goto end;
347e1051a39Sopenharmony_ci        }
348e1051a39Sopenharmony_ci        if (do_verify)
349e1051a39Sopenharmony_ci            if (impl == NULL)
350e1051a39Sopenharmony_ci                res = EVP_DigestVerifyInit_ex(mctx, &pctx, digestname,
351e1051a39Sopenharmony_ci                                              app_get0_libctx(),
352e1051a39Sopenharmony_ci                                              app_get0_propq(), sigkey, NULL);
353e1051a39Sopenharmony_ci            else
354e1051a39Sopenharmony_ci                res = EVP_DigestVerifyInit(mctx, &pctx, md, impl, sigkey);
355e1051a39Sopenharmony_ci        else
356e1051a39Sopenharmony_ci            if (impl == NULL)
357e1051a39Sopenharmony_ci                res = EVP_DigestSignInit_ex(mctx, &pctx, digestname,
358e1051a39Sopenharmony_ci                                            app_get0_libctx(),
359e1051a39Sopenharmony_ci                                            app_get0_propq(), sigkey, NULL);
360e1051a39Sopenharmony_ci            else
361e1051a39Sopenharmony_ci                res = EVP_DigestSignInit(mctx, &pctx, md, impl, sigkey);
362e1051a39Sopenharmony_ci        if (res == 0) {
363e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Error setting context\n");
364e1051a39Sopenharmony_ci            goto end;
365e1051a39Sopenharmony_ci        }
366e1051a39Sopenharmony_ci        if (sigopts != NULL) {
367e1051a39Sopenharmony_ci            for (i = 0; i < sk_OPENSSL_STRING_num(sigopts); i++) {
368e1051a39Sopenharmony_ci                char *sigopt = sk_OPENSSL_STRING_value(sigopts, i);
369e1051a39Sopenharmony_ci
370e1051a39Sopenharmony_ci                if (pkey_ctrl_string(pctx, sigopt) <= 0) {
371e1051a39Sopenharmony_ci                    BIO_printf(bio_err, "Signature parameter error \"%s\"\n",
372e1051a39Sopenharmony_ci                               sigopt);
373e1051a39Sopenharmony_ci                    goto end;
374e1051a39Sopenharmony_ci                }
375e1051a39Sopenharmony_ci            }
376e1051a39Sopenharmony_ci        }
377e1051a39Sopenharmony_ci    }
378e1051a39Sopenharmony_ci    /* we use md as a filter, reading from 'in' */
379e1051a39Sopenharmony_ci    else {
380e1051a39Sopenharmony_ci        EVP_MD_CTX *mctx = NULL;
381e1051a39Sopenharmony_ci        if (BIO_get_md_ctx(bmd, &mctx) <= 0) {
382e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Error getting context\n");
383e1051a39Sopenharmony_ci            goto end;
384e1051a39Sopenharmony_ci        }
385e1051a39Sopenharmony_ci        if (md == NULL)
386e1051a39Sopenharmony_ci            md = (EVP_MD *)EVP_sha256();
387e1051a39Sopenharmony_ci        if (!EVP_DigestInit_ex(mctx, md, impl)) {
388e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Error setting digest\n");
389e1051a39Sopenharmony_ci            goto end;
390e1051a39Sopenharmony_ci        }
391e1051a39Sopenharmony_ci    }
392e1051a39Sopenharmony_ci
393e1051a39Sopenharmony_ci    if (sigfile != NULL && sigkey != NULL) {
394e1051a39Sopenharmony_ci        BIO *sigbio = BIO_new_file(sigfile, "rb");
395e1051a39Sopenharmony_ci
396e1051a39Sopenharmony_ci        if (sigbio == NULL) {
397e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Error opening signature file %s\n", sigfile);
398e1051a39Sopenharmony_ci            goto end;
399e1051a39Sopenharmony_ci        }
400e1051a39Sopenharmony_ci        siglen = EVP_PKEY_get_size(sigkey);
401e1051a39Sopenharmony_ci        sigbuf = app_malloc(siglen, "signature buffer");
402e1051a39Sopenharmony_ci        siglen = BIO_read(sigbio, sigbuf, siglen);
403e1051a39Sopenharmony_ci        BIO_free(sigbio);
404e1051a39Sopenharmony_ci        if (siglen <= 0) {
405e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Error reading signature file %s\n", sigfile);
406e1051a39Sopenharmony_ci            goto end;
407e1051a39Sopenharmony_ci        }
408e1051a39Sopenharmony_ci    }
409e1051a39Sopenharmony_ci    inp = BIO_push(bmd, in);
410e1051a39Sopenharmony_ci
411e1051a39Sopenharmony_ci    if (md == NULL) {
412e1051a39Sopenharmony_ci        EVP_MD_CTX *tctx;
413e1051a39Sopenharmony_ci
414e1051a39Sopenharmony_ci        BIO_get_md_ctx(bmd, &tctx);
415e1051a39Sopenharmony_ci        md = EVP_MD_CTX_get1_md(tctx);
416e1051a39Sopenharmony_ci    }
417e1051a39Sopenharmony_ci    if (md != NULL)
418e1051a39Sopenharmony_ci        md_name = EVP_MD_get0_name(md);
419e1051a39Sopenharmony_ci
420e1051a39Sopenharmony_ci    if (xoflen > 0) {
421e1051a39Sopenharmony_ci        if (!(EVP_MD_get_flags(md) & EVP_MD_FLAG_XOF)) {
422e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Length can only be specified for XOF\n");
423e1051a39Sopenharmony_ci            goto end;
424e1051a39Sopenharmony_ci        }
425e1051a39Sopenharmony_ci        /*
426e1051a39Sopenharmony_ci         * Signing using XOF is not supported by any algorithms currently since
427e1051a39Sopenharmony_ci         * each algorithm only calls EVP_DigestFinal_ex() in their sign_final
428e1051a39Sopenharmony_ci         * and verify_final methods.
429e1051a39Sopenharmony_ci         */
430e1051a39Sopenharmony_ci        if (sigkey != NULL) {
431e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Signing key cannot be specified for XOF\n");
432e1051a39Sopenharmony_ci            goto end;
433e1051a39Sopenharmony_ci        }
434e1051a39Sopenharmony_ci    }
435e1051a39Sopenharmony_ci
436e1051a39Sopenharmony_ci    if (argc == 0) {
437e1051a39Sopenharmony_ci        BIO_set_fp(in, stdin, BIO_NOCLOSE);
438e1051a39Sopenharmony_ci        ret = do_fp(out, buf, inp, separator, out_bin, xoflen, sigkey, sigbuf,
439e1051a39Sopenharmony_ci                    siglen, NULL, md_name, "stdin");
440e1051a39Sopenharmony_ci    } else {
441e1051a39Sopenharmony_ci        const char *sig_name = NULL;
442e1051a39Sopenharmony_ci
443e1051a39Sopenharmony_ci        if (out_bin == 0) {
444e1051a39Sopenharmony_ci            if (sigkey != NULL)
445e1051a39Sopenharmony_ci                sig_name = EVP_PKEY_get0_type_name(sigkey);
446e1051a39Sopenharmony_ci        }
447e1051a39Sopenharmony_ci        ret = EXIT_SUCCESS;
448e1051a39Sopenharmony_ci        for (i = 0; i < argc; i++) {
449e1051a39Sopenharmony_ci            if (BIO_read_filename(in, argv[i]) <= 0) {
450e1051a39Sopenharmony_ci                perror(argv[i]);
451e1051a39Sopenharmony_ci                ret = EXIT_FAILURE;
452e1051a39Sopenharmony_ci                continue;
453e1051a39Sopenharmony_ci            } else {
454e1051a39Sopenharmony_ci                if (do_fp(out, buf, inp, separator, out_bin, xoflen,
455e1051a39Sopenharmony_ci                          sigkey, sigbuf, siglen, sig_name, md_name, argv[i]))
456e1051a39Sopenharmony_ci                    ret = EXIT_FAILURE;
457e1051a39Sopenharmony_ci            }
458e1051a39Sopenharmony_ci            (void)BIO_reset(bmd);
459e1051a39Sopenharmony_ci        }
460e1051a39Sopenharmony_ci    }
461e1051a39Sopenharmony_ci end:
462e1051a39Sopenharmony_ci    if (ret != EXIT_SUCCESS)
463e1051a39Sopenharmony_ci        ERR_print_errors(bio_err);
464e1051a39Sopenharmony_ci    OPENSSL_clear_free(buf, BUFSIZE);
465e1051a39Sopenharmony_ci    BIO_free(in);
466e1051a39Sopenharmony_ci    OPENSSL_free(passin);
467e1051a39Sopenharmony_ci    BIO_free_all(out);
468e1051a39Sopenharmony_ci    EVP_MD_free(md);
469e1051a39Sopenharmony_ci    EVP_PKEY_free(sigkey);
470e1051a39Sopenharmony_ci    sk_OPENSSL_STRING_free(sigopts);
471e1051a39Sopenharmony_ci    sk_OPENSSL_STRING_free(macopts);
472e1051a39Sopenharmony_ci    OPENSSL_free(sigbuf);
473e1051a39Sopenharmony_ci    BIO_free(bmd);
474e1051a39Sopenharmony_ci    release_engine(e);
475e1051a39Sopenharmony_ci    return ret;
476e1051a39Sopenharmony_ci}
477e1051a39Sopenharmony_ci
478e1051a39Sopenharmony_cistatic void show_digests(const OBJ_NAME *name, void *arg)
479e1051a39Sopenharmony_ci{
480e1051a39Sopenharmony_ci    struct doall_dgst_digests *dec = (struct doall_dgst_digests *)arg;
481e1051a39Sopenharmony_ci    const EVP_MD *md = NULL;
482e1051a39Sopenharmony_ci
483e1051a39Sopenharmony_ci    /* Filter out signed digests (a.k.a signature algorithms) */
484e1051a39Sopenharmony_ci    if (strstr(name->name, "rsa") != NULL || strstr(name->name, "RSA") != NULL)
485e1051a39Sopenharmony_ci        return;
486e1051a39Sopenharmony_ci
487e1051a39Sopenharmony_ci    if (!islower((unsigned char)*name->name))
488e1051a39Sopenharmony_ci        return;
489e1051a39Sopenharmony_ci
490e1051a39Sopenharmony_ci    /* Filter out message digests that we cannot use */
491e1051a39Sopenharmony_ci    md = EVP_MD_fetch(app_get0_libctx(), name->name, app_get0_propq());
492e1051a39Sopenharmony_ci    if (md == NULL) {
493e1051a39Sopenharmony_ci        md = EVP_get_digestbyname(name->name);
494e1051a39Sopenharmony_ci        if (md == NULL)
495e1051a39Sopenharmony_ci            return;
496e1051a39Sopenharmony_ci    }
497e1051a39Sopenharmony_ci
498e1051a39Sopenharmony_ci    BIO_printf(dec->bio, "-%-25s", name->name);
499e1051a39Sopenharmony_ci    if (++dec->n == 3) {
500e1051a39Sopenharmony_ci        BIO_printf(dec->bio, "\n");
501e1051a39Sopenharmony_ci        dec->n = 0;
502e1051a39Sopenharmony_ci    } else {
503e1051a39Sopenharmony_ci        BIO_printf(dec->bio, " ");
504e1051a39Sopenharmony_ci    }
505e1051a39Sopenharmony_ci}
506e1051a39Sopenharmony_ci
507e1051a39Sopenharmony_ci/*
508e1051a39Sopenharmony_ci * The newline_escape_filename function performs newline escaping for any
509e1051a39Sopenharmony_ci * filename that contains a newline.  This function also takes a pointer
510e1051a39Sopenharmony_ci * to backslash. The backslash pointer is a flag to indicating whether a newline
511e1051a39Sopenharmony_ci * is present in the filename.  If a newline is present, the backslash flag is
512e1051a39Sopenharmony_ci * set and the output format will contain a backslash at the beginning of the
513e1051a39Sopenharmony_ci * digest output. This output format is to replicate the output format found
514e1051a39Sopenharmony_ci * in the '*sum' checksum programs. This aims to preserve backward
515e1051a39Sopenharmony_ci * compatibility.
516e1051a39Sopenharmony_ci */
517e1051a39Sopenharmony_cistatic const char *newline_escape_filename(const char *file, int * backslash)
518e1051a39Sopenharmony_ci{
519e1051a39Sopenharmony_ci    size_t i, e = 0, length = strlen(file), newline_count = 0, mem_len = 0;
520e1051a39Sopenharmony_ci    char *file_cpy = NULL;
521e1051a39Sopenharmony_ci
522e1051a39Sopenharmony_ci    for (i = 0; i < length; i++)
523e1051a39Sopenharmony_ci        if (file[i] == '\n')
524e1051a39Sopenharmony_ci            newline_count++;
525e1051a39Sopenharmony_ci
526e1051a39Sopenharmony_ci    mem_len = length + newline_count + 1;
527e1051a39Sopenharmony_ci    file_cpy = app_malloc(mem_len, file);
528e1051a39Sopenharmony_ci    i = 0;
529e1051a39Sopenharmony_ci
530e1051a39Sopenharmony_ci    while(e < length) {
531e1051a39Sopenharmony_ci        const char c = file[e];
532e1051a39Sopenharmony_ci        if (c == '\n') {
533e1051a39Sopenharmony_ci            file_cpy[i++] = '\\';
534e1051a39Sopenharmony_ci            file_cpy[i++] = 'n';
535e1051a39Sopenharmony_ci            *backslash = 1;
536e1051a39Sopenharmony_ci        } else {
537e1051a39Sopenharmony_ci            file_cpy[i++] = c;
538e1051a39Sopenharmony_ci        }
539e1051a39Sopenharmony_ci        e++;
540e1051a39Sopenharmony_ci    }
541e1051a39Sopenharmony_ci    file_cpy[i] = '\0';
542e1051a39Sopenharmony_ci    return (const char*)file_cpy;
543e1051a39Sopenharmony_ci}
544e1051a39Sopenharmony_ci
545e1051a39Sopenharmony_ci
546e1051a39Sopenharmony_ciint do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, int xoflen,
547e1051a39Sopenharmony_ci          EVP_PKEY *key, unsigned char *sigin, int siglen,
548e1051a39Sopenharmony_ci          const char *sig_name, const char *md_name,
549e1051a39Sopenharmony_ci          const char *file)
550e1051a39Sopenharmony_ci{
551e1051a39Sopenharmony_ci    size_t len = BUFSIZE;
552e1051a39Sopenharmony_ci    int i, backslash = 0, ret = EXIT_FAILURE;
553e1051a39Sopenharmony_ci    unsigned char *allocated_buf = NULL;
554e1051a39Sopenharmony_ci
555e1051a39Sopenharmony_ci    while (BIO_pending(bp) || !BIO_eof(bp)) {
556e1051a39Sopenharmony_ci        i = BIO_read(bp, (char *)buf, BUFSIZE);
557e1051a39Sopenharmony_ci        if (i < 0) {
558e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Read error in %s\n", file);
559e1051a39Sopenharmony_ci            goto end;
560e1051a39Sopenharmony_ci        }
561e1051a39Sopenharmony_ci        if (i == 0)
562e1051a39Sopenharmony_ci            break;
563e1051a39Sopenharmony_ci    }
564e1051a39Sopenharmony_ci    if (sigin != NULL) {
565e1051a39Sopenharmony_ci        EVP_MD_CTX *ctx;
566e1051a39Sopenharmony_ci        BIO_get_md_ctx(bp, &ctx);
567e1051a39Sopenharmony_ci        i = EVP_DigestVerifyFinal(ctx, sigin, (unsigned int)siglen);
568e1051a39Sopenharmony_ci        if (i > 0) {
569e1051a39Sopenharmony_ci            BIO_printf(out, "Verified OK\n");
570e1051a39Sopenharmony_ci        } else if (i == 0) {
571e1051a39Sopenharmony_ci            BIO_printf(out, "Verification failure\n");
572e1051a39Sopenharmony_ci            goto end;
573e1051a39Sopenharmony_ci        } else {
574e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Error verifying data\n");
575e1051a39Sopenharmony_ci            goto end;
576e1051a39Sopenharmony_ci        }
577e1051a39Sopenharmony_ci        ret = EXIT_SUCCESS;
578e1051a39Sopenharmony_ci        goto end;
579e1051a39Sopenharmony_ci    }
580e1051a39Sopenharmony_ci    if (key != NULL) {
581e1051a39Sopenharmony_ci        EVP_MD_CTX *ctx;
582e1051a39Sopenharmony_ci        size_t tmplen;
583e1051a39Sopenharmony_ci
584e1051a39Sopenharmony_ci        BIO_get_md_ctx(bp, &ctx);
585e1051a39Sopenharmony_ci        if (!EVP_DigestSignFinal(ctx, NULL, &tmplen)) {
586e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Error getting maximum length of signed data\n");
587e1051a39Sopenharmony_ci            goto end;
588e1051a39Sopenharmony_ci        }
589e1051a39Sopenharmony_ci        if (tmplen > BUFSIZE) {
590e1051a39Sopenharmony_ci            len = tmplen;
591e1051a39Sopenharmony_ci            allocated_buf = app_malloc(len, "Signature buffer");
592e1051a39Sopenharmony_ci            buf = allocated_buf;
593e1051a39Sopenharmony_ci        }
594e1051a39Sopenharmony_ci        if (!EVP_DigestSignFinal(ctx, buf, &len)) {
595e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Error signing data\n");
596e1051a39Sopenharmony_ci            goto end;
597e1051a39Sopenharmony_ci        }
598e1051a39Sopenharmony_ci    } else if (xoflen > 0) {
599e1051a39Sopenharmony_ci        EVP_MD_CTX *ctx;
600e1051a39Sopenharmony_ci
601e1051a39Sopenharmony_ci        len = xoflen;
602e1051a39Sopenharmony_ci        if (len > BUFSIZE) {
603e1051a39Sopenharmony_ci            allocated_buf = app_malloc(len, "Digest buffer");
604e1051a39Sopenharmony_ci            buf = allocated_buf;
605e1051a39Sopenharmony_ci        }
606e1051a39Sopenharmony_ci
607e1051a39Sopenharmony_ci        BIO_get_md_ctx(bp, &ctx);
608e1051a39Sopenharmony_ci
609e1051a39Sopenharmony_ci        if (!EVP_DigestFinalXOF(ctx, buf, len)) {
610e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Error Digesting Data\n");
611e1051a39Sopenharmony_ci            goto end;
612e1051a39Sopenharmony_ci        }
613e1051a39Sopenharmony_ci    } else {
614e1051a39Sopenharmony_ci        len = BIO_gets(bp, (char *)buf, BUFSIZE);
615e1051a39Sopenharmony_ci        if ((int)len < 0)
616e1051a39Sopenharmony_ci            goto end;
617e1051a39Sopenharmony_ci    }
618e1051a39Sopenharmony_ci
619e1051a39Sopenharmony_ci    if (binout) {
620e1051a39Sopenharmony_ci        BIO_write(out, buf, len);
621e1051a39Sopenharmony_ci    } else if (sep == 2) {
622e1051a39Sopenharmony_ci        file = newline_escape_filename(file, &backslash);
623e1051a39Sopenharmony_ci
624e1051a39Sopenharmony_ci        if (backslash == 1)
625e1051a39Sopenharmony_ci            BIO_puts(out, "\\");
626e1051a39Sopenharmony_ci
627e1051a39Sopenharmony_ci        for (i = 0; i < (int)len; i++)
628e1051a39Sopenharmony_ci            BIO_printf(out, "%02x", buf[i]);
629e1051a39Sopenharmony_ci
630e1051a39Sopenharmony_ci        BIO_printf(out, " *%s\n", file);
631e1051a39Sopenharmony_ci        OPENSSL_free((char *)file);
632e1051a39Sopenharmony_ci    } else {
633e1051a39Sopenharmony_ci        if (sig_name != NULL) {
634e1051a39Sopenharmony_ci            BIO_puts(out, sig_name);
635e1051a39Sopenharmony_ci            if (md_name != NULL)
636e1051a39Sopenharmony_ci                BIO_printf(out, "-%s", md_name);
637e1051a39Sopenharmony_ci            BIO_printf(out, "(%s)= ", file);
638e1051a39Sopenharmony_ci        } else if (md_name != NULL) {
639e1051a39Sopenharmony_ci            BIO_printf(out, "%s(%s)= ", md_name, file);
640e1051a39Sopenharmony_ci        } else {
641e1051a39Sopenharmony_ci            BIO_printf(out, "(%s)= ", file);
642e1051a39Sopenharmony_ci        }
643e1051a39Sopenharmony_ci        for (i = 0; i < (int)len; i++) {
644e1051a39Sopenharmony_ci            if (sep && (i != 0))
645e1051a39Sopenharmony_ci                BIO_printf(out, ":");
646e1051a39Sopenharmony_ci            BIO_printf(out, "%02x", buf[i]);
647e1051a39Sopenharmony_ci        }
648e1051a39Sopenharmony_ci        BIO_printf(out, "\n");
649e1051a39Sopenharmony_ci    }
650e1051a39Sopenharmony_ci
651e1051a39Sopenharmony_ci    ret = EXIT_SUCCESS;
652e1051a39Sopenharmony_ci end:
653e1051a39Sopenharmony_ci    if (allocated_buf != NULL)
654e1051a39Sopenharmony_ci        OPENSSL_clear_free(allocated_buf, len);
655e1051a39Sopenharmony_ci
656e1051a39Sopenharmony_ci    return ret;
657e1051a39Sopenharmony_ci}
658