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