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