diff options
Diffstat (limited to 'apps/dgst.c')
-rw-r--r-- | apps/dgst.c | 126 |
1 files changed, 115 insertions, 11 deletions
diff --git a/apps/dgst.c b/apps/dgst.c index d6f5a0e2e712..e595f7d8186f 100644 --- a/apps/dgst.c +++ b/apps/dgst.c @@ -19,6 +19,7 @@ #include <openssl/x509.h> #include <openssl/pem.h> #include <openssl/hmac.h> +#include <ctype.h> #undef BUFSIZE #define BUFSIZE 1024*8 @@ -27,9 +28,15 @@ 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_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, @@ -43,6 +50,7 @@ const OPTIONS dgst_options[] = { {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"}, @@ -91,6 +99,7 @@ int dgst_main(int argc, char **argv) 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"); @@ -108,6 +117,15 @@ 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; @@ -413,20 +431,86 @@ int dgst_main(int argc, char **argv) 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; - int i; + 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); - return 1; + goto end; } if (i == 0) break; @@ -439,37 +523,51 @@ int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, BIO_printf(out, "Verified OK\n"); } 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 != NULL) { EVP_MD_CTX *ctx; + int pkey_len; BIO_get_md_ctx(bp, &ctx); - len = BUFSIZE; + 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); - 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) { 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); @@ -488,5 +586,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; } |