1 /* 2 * Copyright 2018-2022 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #include <string.h> 11 12 #include "apps.h" 13 #include "progs.h" 14 #include <openssl/bio.h> 15 #include <openssl/err.h> 16 #include <openssl/evp.h> 17 #include <openssl/params.h> 18 #include <openssl/core_names.h> 19 20 #undef BUFSIZE 21 #define BUFSIZE 1024*8 22 23 typedef enum OPTION_choice { 24 OPT_COMMON, 25 OPT_MACOPT, OPT_BIN, OPT_IN, OPT_OUT, 26 OPT_CIPHER, OPT_DIGEST, 27 OPT_PROV_ENUM 28 } OPTION_CHOICE; 29 30 const OPTIONS mac_options[] = { 31 {OPT_HELP_STR, 1, '-', "Usage: %s [options] mac_name\n"}, 32 33 OPT_SECTION("General"), 34 {"help", OPT_HELP, '-', "Display this summary"}, 35 {"macopt", OPT_MACOPT, 's', "MAC algorithm parameters in n:v form"}, 36 {"cipher", OPT_CIPHER, 's', "Cipher"}, 37 {"digest", OPT_DIGEST, 's', "Digest"}, 38 {OPT_MORE_STR, 1, '-', "See 'PARAMETER NAMES' in the EVP_MAC_ docs"}, 39 40 OPT_SECTION("Input"), 41 {"in", OPT_IN, '<', "Input file to MAC (default is stdin)"}, 42 43 OPT_SECTION("Output"), 44 {"out", OPT_OUT, '>', "Output to filename rather than stdout"}, 45 {"binary", OPT_BIN, '-', 46 "Output in binary format (default is hexadecimal)"}, 47 48 OPT_PROV_OPTIONS, 49 50 OPT_PARAMETERS(), 51 {"mac_name", 0, 0, "MAC algorithm"}, 52 {NULL} 53 }; 54 55 static char *alloc_mac_algorithm_name(STACK_OF(OPENSSL_STRING) **optp, 56 const char *name, const char *arg) 57 { 58 size_t len = strlen(name) + strlen(arg) + 2; 59 char *res; 60 61 if (*optp == NULL) 62 *optp = sk_OPENSSL_STRING_new_null(); 63 if (*optp == NULL) 64 return NULL; 65 66 res = app_malloc(len, "algorithm name"); 67 BIO_snprintf(res, len, "%s:%s", name, arg); 68 if (sk_OPENSSL_STRING_push(*optp, res)) 69 return res; 70 OPENSSL_free(res); 71 return NULL; 72 } 73 74 int mac_main(int argc, char **argv) 75 { 76 int ret = 1; 77 char *prog; 78 EVP_MAC *mac = NULL; 79 OPTION_CHOICE o; 80 EVP_MAC_CTX *ctx = NULL; 81 STACK_OF(OPENSSL_STRING) *opts = NULL; 82 unsigned char *buf = NULL; 83 size_t len; 84 int i; 85 BIO *in = NULL, *out = NULL; 86 const char *outfile = NULL; 87 const char *infile = NULL; 88 int out_bin = 0; 89 int inform = FORMAT_BINARY; 90 char *digest = NULL, *cipher = NULL; 91 OSSL_PARAM *params = NULL; 92 93 prog = opt_init(argc, argv, mac_options); 94 buf = app_malloc(BUFSIZE, "I/O buffer"); 95 while ((o = opt_next()) != OPT_EOF) { 96 switch (o) { 97 default: 98 opthelp: 99 BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); 100 goto err; 101 case OPT_HELP: 102 opt_help(mac_options); 103 ret = 0; 104 goto err; 105 case OPT_BIN: 106 out_bin = 1; 107 break; 108 case OPT_IN: 109 infile = opt_arg(); 110 break; 111 case OPT_OUT: 112 outfile = opt_arg(); 113 break; 114 case OPT_MACOPT: 115 if (opts == NULL) 116 opts = sk_OPENSSL_STRING_new_null(); 117 if (opts == NULL || !sk_OPENSSL_STRING_push(opts, opt_arg())) 118 goto opthelp; 119 break; 120 case OPT_CIPHER: 121 OPENSSL_free(cipher); 122 cipher = alloc_mac_algorithm_name(&opts, "cipher", opt_arg()); 123 if (cipher == NULL) 124 goto opthelp; 125 break; 126 case OPT_DIGEST: 127 OPENSSL_free(digest); 128 digest = alloc_mac_algorithm_name(&opts, "digest", opt_arg()); 129 if (digest == NULL) 130 goto opthelp; 131 break; 132 case OPT_PROV_CASES: 133 if (!opt_provider(o)) 134 goto err; 135 break; 136 } 137 } 138 139 /* One argument, the MAC name. */ 140 argc = opt_num_rest(); 141 argv = opt_rest(); 142 if (argc != 1) 143 goto opthelp; 144 145 mac = EVP_MAC_fetch(app_get0_libctx(), argv[0], app_get0_propq()); 146 if (mac == NULL) { 147 BIO_printf(bio_err, "Invalid MAC name %s\n", argv[0]); 148 goto opthelp; 149 } 150 151 ctx = EVP_MAC_CTX_new(mac); 152 if (ctx == NULL) 153 goto err; 154 155 if (opts != NULL) { 156 int ok = 1; 157 158 params = app_params_new_from_opts(opts, 159 EVP_MAC_settable_ctx_params(mac)); 160 if (params == NULL) 161 goto err; 162 163 if (!EVP_MAC_CTX_set_params(ctx, params)) { 164 BIO_printf(bio_err, "MAC parameter error\n"); 165 ERR_print_errors(bio_err); 166 ok = 0; 167 } 168 app_params_free(params); 169 if (!ok) 170 goto err; 171 } 172 173 in = bio_open_default(infile, 'r', inform); 174 if (in == NULL) 175 goto err; 176 177 out = bio_open_default(outfile, 'w', out_bin ? FORMAT_BINARY : FORMAT_TEXT); 178 if (out == NULL) 179 goto err; 180 181 if (!EVP_MAC_init(ctx, NULL, 0, NULL)) { 182 BIO_printf(bio_err, "EVP_MAC_Init failed\n"); 183 goto err; 184 } 185 186 while (BIO_pending(in) || !BIO_eof(in)) { 187 i = BIO_read(in, (char *)buf, BUFSIZE); 188 if (i < 0) { 189 BIO_printf(bio_err, "Read Error in '%s'\n", infile); 190 ERR_print_errors(bio_err); 191 goto err; 192 } 193 if (i == 0) 194 break; 195 if (!EVP_MAC_update(ctx, buf, i)) { 196 BIO_printf(bio_err, "EVP_MAC_update failed\n"); 197 goto err; 198 } 199 } 200 201 if (!EVP_MAC_final(ctx, NULL, &len, 0)) { 202 BIO_printf(bio_err, "EVP_MAC_final failed\n"); 203 goto err; 204 } 205 if (len > BUFSIZE) { 206 BIO_printf(bio_err, "output len is too large\n"); 207 goto err; 208 } 209 210 if (!EVP_MAC_final(ctx, buf, &len, BUFSIZE)) { 211 BIO_printf(bio_err, "EVP_MAC_final failed\n"); 212 goto err; 213 } 214 215 if (out_bin) { 216 BIO_write(out, buf, len); 217 } else { 218 for (i = 0; i < (int)len; ++i) 219 BIO_printf(out, "%02X", buf[i]); 220 if (outfile == NULL) 221 BIO_printf(out,"\n"); 222 } 223 224 ret = 0; 225 err: 226 if (ret != 0) 227 ERR_print_errors(bio_err); 228 OPENSSL_clear_free(buf, BUFSIZE); 229 OPENSSL_free(cipher); 230 OPENSSL_free(digest); 231 sk_OPENSSL_STRING_free(opts); 232 BIO_free(in); 233 BIO_free(out); 234 EVP_MAC_CTX_free(ctx); 235 EVP_MAC_free(mac); 236 return ret; 237 } 238