Annotation of src/usr.bin/openssl/dgst.c, Revision 1.14
1.14 ! inoguchi 1: /* $OpenBSD: dgst.c,v 1.13 2019/01/18 23:33:57 naddy Exp $ */
1.1 jsing 2: /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3: * All rights reserved.
4: *
5: * This package is an SSL implementation written
6: * by Eric Young (eay@cryptsoft.com).
7: * The implementation was written so as to conform with Netscapes SSL.
8: *
9: * This library is free for commercial and non-commercial use as long as
10: * the following conditions are aheared to. The following conditions
11: * apply to all code found in this distribution, be it the RC4, RSA,
12: * lhash, DES, etc., code; not just the SSL code. The SSL documentation
13: * included with this distribution is covered by the same copyright terms
14: * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15: *
16: * Copyright remains Eric Young's, and as such any Copyright notices in
17: * the code are not to be removed.
18: * If this package is used in a product, Eric Young should be given attribution
19: * as the author of the parts of the library used.
20: * This can be in the form of a textual message at program startup or
21: * in documentation (online or textual) provided with the package.
22: *
23: * Redistribution and use in source and binary forms, with or without
24: * modification, are permitted provided that the following conditions
25: * are met:
26: * 1. Redistributions of source code must retain the copyright
27: * notice, this list of conditions and the following disclaimer.
28: * 2. Redistributions in binary form must reproduce the above copyright
29: * notice, this list of conditions and the following disclaimer in the
30: * documentation and/or other materials provided with the distribution.
31: * 3. All advertising materials mentioning features or use of this software
32: * must display the following acknowledgement:
33: * "This product includes cryptographic software written by
34: * Eric Young (eay@cryptsoft.com)"
35: * The word 'cryptographic' can be left out if the rouines from the library
36: * being used are not cryptographic related :-).
37: * 4. If you include any Windows specific code (or a derivative thereof) from
38: * the apps directory (application code) you must include an acknowledgement:
39: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40: *
41: * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51: * SUCH DAMAGE.
52: *
53: * The licence and distribution terms for any publically available version or
54: * derivative of this code cannot be changed. i.e. this code cannot simply be
55: * copied and put under another distribution licence
56: * [including the GNU Public Licence.]
57: */
58:
59: #include <stdio.h>
60: #include <stdlib.h>
61: #include <string.h>
62:
63: #include "apps.h"
64:
65: #include <openssl/bio.h>
66: #include <openssl/err.h>
67: #include <openssl/evp.h>
68: #include <openssl/hmac.h>
69: #include <openssl/objects.h>
70: #include <openssl/pem.h>
71: #include <openssl/x509.h>
72:
73: #define BUFSIZE 1024*8
74:
75: int
76: do_fp(BIO * out, unsigned char *buf, BIO * bp, int sep, int binout,
77: EVP_PKEY * key, unsigned char *sigin, int siglen,
78: const char *sig_name, const char *md_name,
79: const char *file, BIO * bmd);
80:
1.14 ! inoguchi 81: static struct {
! 82: int argsused;
! 83: int debug;
! 84: int do_verify;
! 85: char *hmac_key;
! 86: char *keyfile;
! 87: int keyform;
! 88: const EVP_MD *m;
! 89: char *mac_name;
! 90: STACK_OF(OPENSSL_STRING) *macopts;
! 91: const EVP_MD *md;
! 92: int out_bin;
! 93: char *outfile;
! 94: char *passargin;
! 95: int separator;
! 96: char *sigfile;
! 97: STACK_OF(OPENSSL_STRING) *sigopts;
! 98: int want_pub;
! 99: } dgst_config;
! 100:
1.1 jsing 101: static void
102: list_md_fn(const EVP_MD * m, const char *from, const char *to, void *arg)
103: {
104: const char *mname;
105: /* Skip aliases */
106: if (!m)
107: return;
108: mname = OBJ_nid2ln(EVP_MD_type(m));
109: /* Skip shortnames */
110: if (strcmp(from, mname))
111: return;
112: /* Skip clones */
113: if (EVP_MD_flags(m) & EVP_MD_FLAG_PKEY_DIGEST)
114: return;
115: if (strchr(mname, ' '))
116: mname = EVP_MD_name(m);
117: BIO_printf(arg, "-%-14s to use the %s message digest algorithm\n",
118: mname, mname);
119: }
120:
121: int
122: dgst_main(int argc, char **argv)
123: {
124: unsigned char *buf = NULL;
125: int i, err = 1;
126: BIO *in = NULL, *inp;
127: BIO *bmd = NULL;
128: BIO *out = NULL;
129: #define PROG_NAME_SIZE 39
130: char pname[PROG_NAME_SIZE + 1];
131: EVP_PKEY *sigkey = NULL;
132: unsigned char *sigbuf = NULL;
133: int siglen = 0;
1.14 ! inoguchi 134: char *passin = NULL;
1.7 doug 135:
136: if (single_execution) {
1.10 deraadt 137: if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
1.7 doug 138: perror("pledge");
1.9 doug 139: exit(1);
140: }
1.7 doug 141: }
1.1 jsing 142:
143: if ((buf = malloc(BUFSIZE)) == NULL) {
144: BIO_printf(bio_err, "out of memory\n");
145: goto end;
146: }
147:
1.14 ! inoguchi 148: memset(&dgst_config, 0, sizeof(dgst_config));
! 149: dgst_config.keyform = FORMAT_PEM;
! 150: dgst_config.out_bin = -1;
! 151:
1.1 jsing 152: /* first check the program name */
153: program_name(argv[0], pname, sizeof pname);
154:
1.14 ! inoguchi 155: dgst_config.md = EVP_get_digestbyname(pname);
1.1 jsing 156:
157: argc--;
158: argv++;
159: while (argc > 0) {
160: if ((*argv)[0] != '-')
161: break;
162: if (strcmp(*argv, "-c") == 0)
1.14 ! inoguchi 163: dgst_config.separator = 1;
1.1 jsing 164: else if (strcmp(*argv, "-r") == 0)
1.14 ! inoguchi 165: dgst_config.separator = 2;
1.1 jsing 166: else if (strcmp(*argv, "-out") == 0) {
167: if (--argc < 1)
168: break;
1.14 ! inoguchi 169: dgst_config.outfile = *(++argv);
1.1 jsing 170: } else if (strcmp(*argv, "-sign") == 0) {
171: if (--argc < 1)
172: break;
1.14 ! inoguchi 173: dgst_config.keyfile = *(++argv);
1.1 jsing 174: } else if (!strcmp(*argv, "-passin")) {
175: if (--argc < 1)
176: break;
1.14 ! inoguchi 177: dgst_config.passargin = *++argv;
1.1 jsing 178: } else if (strcmp(*argv, "-verify") == 0) {
179: if (--argc < 1)
180: break;
1.14 ! inoguchi 181: dgst_config.keyfile = *(++argv);
! 182: dgst_config.want_pub = 1;
! 183: dgst_config.do_verify = 1;
1.1 jsing 184: } else if (strcmp(*argv, "-prverify") == 0) {
185: if (--argc < 1)
186: break;
1.14 ! inoguchi 187: dgst_config.keyfile = *(++argv);
! 188: dgst_config.do_verify = 1;
1.1 jsing 189: } else if (strcmp(*argv, "-signature") == 0) {
190: if (--argc < 1)
191: break;
1.14 ! inoguchi 192: dgst_config.sigfile = *(++argv);
1.1 jsing 193: } else if (strcmp(*argv, "-keyform") == 0) {
194: if (--argc < 1)
195: break;
1.14 ! inoguchi 196: dgst_config.keyform = str2fmt(*(++argv));
1.1 jsing 197: }
198: else if (strcmp(*argv, "-hex") == 0)
1.14 ! inoguchi 199: dgst_config.out_bin = 0;
1.1 jsing 200: else if (strcmp(*argv, "-binary") == 0)
1.14 ! inoguchi 201: dgst_config.out_bin = 1;
1.1 jsing 202: else if (strcmp(*argv, "-d") == 0)
1.14 ! inoguchi 203: dgst_config.debug = 1;
1.1 jsing 204: else if (!strcmp(*argv, "-hmac")) {
205: if (--argc < 1)
206: break;
1.14 ! inoguchi 207: dgst_config.hmac_key = *++argv;
1.1 jsing 208: } else if (!strcmp(*argv, "-mac")) {
209: if (--argc < 1)
210: break;
1.14 ! inoguchi 211: dgst_config.mac_name = *++argv;
1.1 jsing 212: } else if (strcmp(*argv, "-sigopt") == 0) {
213: if (--argc < 1)
214: break;
1.14 ! inoguchi 215: if (!dgst_config.sigopts)
! 216: dgst_config.sigopts = sk_OPENSSL_STRING_new_null();
! 217: if (!dgst_config.sigopts || !sk_OPENSSL_STRING_push(dgst_config.sigopts, *(++argv)))
1.1 jsing 218: break;
219: } else if (strcmp(*argv, "-macopt") == 0) {
220: if (--argc < 1)
221: break;
1.14 ! inoguchi 222: if (!dgst_config.macopts)
! 223: dgst_config.macopts = sk_OPENSSL_STRING_new_null();
! 224: if (!dgst_config.macopts || !sk_OPENSSL_STRING_push(dgst_config.macopts, *(++argv)))
1.1 jsing 225: break;
1.14 ! inoguchi 226: } else if ((dgst_config.m = EVP_get_digestbyname(&((*argv)[1]))) != NULL)
! 227: dgst_config.md = dgst_config.m;
1.1 jsing 228: else
229: break;
230: argc--;
231: argv++;
232: }
233:
1.14 ! inoguchi 234: if (dgst_config.do_verify && !dgst_config.sigfile) {
1.1 jsing 235: BIO_printf(bio_err, "No signature to verify: use the -signature option\n");
236: goto end;
237: }
238: if ((argc > 0) && (argv[0][0] == '-')) { /* bad option */
239: BIO_printf(bio_err, "unknown option '%s'\n", *argv);
240: BIO_printf(bio_err, "options are\n");
241: BIO_printf(bio_err, "-c to output the digest with separating colons\n");
242: BIO_printf(bio_err, "-r to output the digest in coreutils format\n");
243: BIO_printf(bio_err, "-d to output debug info\n");
244: BIO_printf(bio_err, "-hex output as hex dump\n");
245: BIO_printf(bio_err, "-binary output in binary form\n");
246: BIO_printf(bio_err, "-sign file sign digest using private key in file\n");
247: BIO_printf(bio_err, "-verify file verify a signature using public key in file\n");
248: BIO_printf(bio_err, "-prverify file verify a signature using private key in file\n");
1.6 bcook 249: BIO_printf(bio_err, "-keyform arg key file format (PEM)\n");
1.1 jsing 250: BIO_printf(bio_err, "-out filename output to filename rather than stdout\n");
251: BIO_printf(bio_err, "-signature file signature to verify\n");
252: BIO_printf(bio_err, "-sigopt nm:v signature parameter\n");
253: BIO_printf(bio_err, "-hmac key create hashed MAC with key\n");
254: BIO_printf(bio_err, "-mac algorithm create MAC (not neccessarily HMAC)\n");
255: BIO_printf(bio_err, "-macopt nm:v MAC algorithm parameters or key\n");
256:
257: EVP_MD_do_all_sorted(list_md_fn, bio_err);
258: goto end;
259: }
1.2 doug 260:
1.1 jsing 261: in = BIO_new(BIO_s_file());
262: bmd = BIO_new(BIO_f_md());
1.2 doug 263: if (in == NULL || bmd == NULL) {
264: ERR_print_errors(bio_err);
265: goto end;
266: }
267:
1.14 ! inoguchi 268: if (dgst_config.debug) {
1.1 jsing 269: BIO_set_callback(in, BIO_debug_callback);
270: /* needed for windows 3.1 */
271: BIO_set_callback_arg(in, (char *) bio_err);
272: }
1.14 ! inoguchi 273: if (!app_passwd(bio_err, dgst_config.passargin, NULL, &passin, NULL)) {
1.1 jsing 274: BIO_printf(bio_err, "Error getting password\n");
275: goto end;
276: }
1.14 ! inoguchi 277: if (dgst_config.out_bin == -1) {
! 278: if (dgst_config.keyfile)
! 279: dgst_config.out_bin = 1;
1.1 jsing 280: else
1.14 ! inoguchi 281: dgst_config.out_bin = 0;
1.1 jsing 282: }
283:
1.14 ! inoguchi 284: if (dgst_config.outfile) {
! 285: if (dgst_config.out_bin)
! 286: out = BIO_new_file(dgst_config.outfile, "wb");
1.1 jsing 287: else
1.14 ! inoguchi 288: out = BIO_new_file(dgst_config.outfile, "w");
1.1 jsing 289: } else {
290: out = BIO_new_fp(stdout, BIO_NOCLOSE);
291: }
292:
293: if (!out) {
294: BIO_printf(bio_err, "Error opening output file %s\n",
1.14 ! inoguchi 295: dgst_config.outfile ? dgst_config.outfile : "(stdout)");
1.1 jsing 296: ERR_print_errors(bio_err);
297: goto end;
298: }
1.14 ! inoguchi 299: if ((!!dgst_config.mac_name + !!dgst_config.keyfile + !!dgst_config.hmac_key) > 1) {
1.1 jsing 300: BIO_printf(bio_err, "MAC and Signing key cannot both be specified\n");
301: goto end;
302: }
1.14 ! inoguchi 303: if (dgst_config.keyfile) {
! 304: if (dgst_config.want_pub)
! 305: sigkey = load_pubkey(bio_err, dgst_config.keyfile, dgst_config.keyform, 0, NULL,
1.6 bcook 306: "key file");
1.1 jsing 307: else
1.14 ! inoguchi 308: sigkey = load_key(bio_err, dgst_config.keyfile, dgst_config.keyform, 0, passin,
1.6 bcook 309: "key file");
1.1 jsing 310: if (!sigkey) {
311: /*
312: * load_[pub]key() has already printed an appropriate
313: * message
314: */
315: goto end;
316: }
317: }
1.14 ! inoguchi 318: if (dgst_config.mac_name) {
1.1 jsing 319: EVP_PKEY_CTX *mac_ctx = NULL;
320: int r = 0;
1.14 ! inoguchi 321: if (!init_gen_str(bio_err, &mac_ctx, dgst_config.mac_name, 0))
1.1 jsing 322: goto mac_end;
1.14 ! inoguchi 323: if (dgst_config.macopts) {
1.1 jsing 324: char *macopt;
1.14 ! inoguchi 325: for (i = 0; i < sk_OPENSSL_STRING_num(dgst_config.macopts); i++) {
! 326: macopt = sk_OPENSSL_STRING_value(dgst_config.macopts, i);
1.1 jsing 327: if (pkey_ctrl_string(mac_ctx, macopt) <= 0) {
328: BIO_printf(bio_err,
329: "MAC parameter error \"%s\"\n",
330: macopt);
331: ERR_print_errors(bio_err);
332: goto mac_end;
333: }
334: }
335: }
336: if (EVP_PKEY_keygen(mac_ctx, &sigkey) <= 0) {
337: BIO_puts(bio_err, "Error generating key\n");
338: ERR_print_errors(bio_err);
339: goto mac_end;
340: }
341: r = 1;
342: mac_end:
343: if (mac_ctx)
344: EVP_PKEY_CTX_free(mac_ctx);
345: if (r == 0)
346: goto end;
347: }
1.14 ! inoguchi 348: if (dgst_config.hmac_key) {
1.6 bcook 349: sigkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL,
1.14 ! inoguchi 350: (unsigned char *) dgst_config.hmac_key, -1);
1.1 jsing 351: if (!sigkey)
352: goto end;
353: }
354: if (sigkey) {
355: EVP_MD_CTX *mctx = NULL;
356: EVP_PKEY_CTX *pctx = NULL;
357: int r;
358: if (!BIO_get_md_ctx(bmd, &mctx)) {
359: BIO_printf(bio_err, "Error getting context\n");
360: ERR_print_errors(bio_err);
361: goto end;
362: }
1.14 ! inoguchi 363: if (dgst_config.do_verify)
! 364: r = EVP_DigestVerifyInit(mctx, &pctx, dgst_config.md, NULL, sigkey);
1.1 jsing 365: else
1.14 ! inoguchi 366: r = EVP_DigestSignInit(mctx, &pctx, dgst_config.md, NULL, sigkey);
1.1 jsing 367: if (!r) {
368: BIO_printf(bio_err, "Error setting context\n");
369: ERR_print_errors(bio_err);
370: goto end;
371: }
1.14 ! inoguchi 372: if (dgst_config.sigopts) {
1.1 jsing 373: char *sigopt;
1.14 ! inoguchi 374: for (i = 0; i < sk_OPENSSL_STRING_num(dgst_config.sigopts); i++) {
! 375: sigopt = sk_OPENSSL_STRING_value(dgst_config.sigopts, i);
1.1 jsing 376: if (pkey_ctrl_string(pctx, sigopt) <= 0) {
377: BIO_printf(bio_err,
378: "parameter error \"%s\"\n",
379: sigopt);
380: ERR_print_errors(bio_err);
381: goto end;
382: }
383: }
384: }
385: }
386: /* we use md as a filter, reading from 'in' */
387: else {
1.14 ! inoguchi 388: if (dgst_config.md == NULL)
! 389: dgst_config.md = EVP_sha256();
! 390: if (!BIO_set_md(bmd, dgst_config.md)) {
1.1 jsing 391: BIO_printf(bio_err, "Error setting digest %s\n", pname);
392: ERR_print_errors(bio_err);
393: goto end;
394: }
395: }
396:
1.14 ! inoguchi 397: if (dgst_config.sigfile && sigkey) {
1.1 jsing 398: BIO *sigbio;
399: siglen = EVP_PKEY_size(sigkey);
400: sigbuf = malloc(siglen);
1.3 rpointel 401: if (sigbuf == NULL) {
402: BIO_printf(bio_err, "out of memory\n");
403: ERR_print_errors(bio_err);
404: goto end;
405: }
1.14 ! inoguchi 406: sigbio = BIO_new_file(dgst_config.sigfile, "rb");
1.1 jsing 407: if (!sigbio) {
408: BIO_printf(bio_err, "Error opening signature file %s\n",
1.14 ! inoguchi 409: dgst_config.sigfile);
1.1 jsing 410: ERR_print_errors(bio_err);
411: goto end;
412: }
413: siglen = BIO_read(sigbio, sigbuf, siglen);
414: BIO_free(sigbio);
415: if (siglen <= 0) {
416: BIO_printf(bio_err, "Error reading signature file %s\n",
1.14 ! inoguchi 417: dgst_config.sigfile);
1.1 jsing 418: ERR_print_errors(bio_err);
419: goto end;
420: }
421: }
422: inp = BIO_push(bmd, in);
423:
1.14 ! inoguchi 424: if (dgst_config.md == NULL) {
1.1 jsing 425: EVP_MD_CTX *tctx;
426: BIO_get_md_ctx(bmd, &tctx);
1.14 ! inoguchi 427: dgst_config.md = EVP_MD_CTX_md(tctx);
1.1 jsing 428: }
429: if (argc == 0) {
430: BIO_set_fp(in, stdin, BIO_NOCLOSE);
1.14 ! inoguchi 431: err = do_fp(out, buf, inp, dgst_config.separator, dgst_config.out_bin, sigkey, sigbuf,
1.1 jsing 432: siglen, NULL, NULL, "stdin", bmd);
433: } else {
434: const char *md_name = NULL, *sig_name = NULL;
1.14 ! inoguchi 435: if (!dgst_config.out_bin) {
1.1 jsing 436: if (sigkey) {
437: const EVP_PKEY_ASN1_METHOD *ameth;
438: ameth = EVP_PKEY_get0_asn1(sigkey);
439: if (ameth)
440: EVP_PKEY_asn1_get0_info(NULL, NULL,
441: NULL, NULL, &sig_name, ameth);
442: }
1.14 ! inoguchi 443: md_name = EVP_MD_name(dgst_config.md);
1.1 jsing 444: }
445: err = 0;
446: for (i = 0; i < argc; i++) {
447: int r;
448: if (BIO_read_filename(in, argv[i]) <= 0) {
449: perror(argv[i]);
450: err++;
451: continue;
452: } else {
1.14 ! inoguchi 453: r = do_fp(out, buf, inp, dgst_config.separator, dgst_config.out_bin,
1.1 jsing 454: sigkey, sigbuf, siglen, sig_name, md_name,
455: argv[i], bmd);
456: }
457: if (r)
458: err = r;
459: (void) BIO_reset(bmd);
460: }
461: }
462:
1.12 jsing 463: end:
1.11 deraadt 464: freezero(buf, BUFSIZE);
1.1 jsing 465: if (in != NULL)
466: BIO_free(in);
467: free(passin);
468: BIO_free_all(out);
469: EVP_PKEY_free(sigkey);
1.14 ! inoguchi 470: if (dgst_config.sigopts)
! 471: sk_OPENSSL_STRING_free(dgst_config.sigopts);
! 472: if (dgst_config.macopts)
! 473: sk_OPENSSL_STRING_free(dgst_config.macopts);
1.1 jsing 474: free(sigbuf);
475: if (bmd != NULL)
476: BIO_free(bmd);
477:
478: return (err);
479: }
480:
481: int
482: do_fp(BIO * out, unsigned char *buf, BIO * bp, int sep, int binout,
483: EVP_PKEY * key, unsigned char *sigin, int siglen,
484: const char *sig_name, const char *md_name,
485: const char *file, BIO * bmd)
486: {
487: size_t len;
488: int i;
489:
490: for (;;) {
491: i = BIO_read(bp, (char *) buf, BUFSIZE);
492: if (i < 0) {
493: BIO_printf(bio_err, "Read Error in %s\n", file);
494: ERR_print_errors(bio_err);
495: return 1;
496: }
497: if (i == 0)
498: break;
499: }
500: if (sigin) {
501: EVP_MD_CTX *ctx;
502: BIO_get_md_ctx(bp, &ctx);
503: i = EVP_DigestVerifyFinal(ctx, sigin, (unsigned int) siglen);
504: if (i > 0)
505: BIO_printf(out, "Verified OK\n");
506: else if (i == 0) {
507: BIO_printf(out, "Verification Failure\n");
508: return 1;
509: } else {
510: BIO_printf(bio_err, "Error Verifying Data\n");
511: ERR_print_errors(bio_err);
512: return 1;
513: }
514: return 0;
515: }
516: if (key) {
517: EVP_MD_CTX *ctx;
518: BIO_get_md_ctx(bp, &ctx);
519: len = BUFSIZE;
520: if (!EVP_DigestSignFinal(ctx, buf, &len)) {
521: BIO_printf(bio_err, "Error Signing Data\n");
522: ERR_print_errors(bio_err);
523: return 1;
524: }
525: } else {
526: len = BIO_gets(bp, (char *) buf, BUFSIZE);
527: if ((int) len < 0) {
528: ERR_print_errors(bio_err);
529: return 1;
530: }
531: }
532:
533: if (binout)
534: BIO_write(out, buf, len);
535: else if (sep == 2) {
536: for (i = 0; i < (int) len; i++)
537: BIO_printf(out, "%02x", buf[i]);
538: BIO_printf(out, " *%s\n", file);
539: } else {
540: if (sig_name)
541: BIO_printf(out, "%s-%s(%s)= ", sig_name, md_name, file);
542: else if (md_name)
543: BIO_printf(out, "%s(%s)= ", md_name, file);
544: else
545: BIO_printf(out, "(%s)= ", file);
546: for (i = 0; i < (int) len; i++) {
547: if (sep && (i != 0))
548: BIO_printf(out, ":");
549: BIO_printf(out, "%02x", buf[i]);
550: }
551: BIO_printf(out, "\n");
552: }
553: return 0;
554: }