Home | History | Annotate | Line # | Download | only in apps
      1  1.1  christos /*
      2  1.1  christos  * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
      3  1.1  christos  *
      4  1.1  christos  * Licensed under the Apache License 2.0 (the "License").  You may not use
      5  1.1  christos  * this file except in compliance with the License.  You can obtain a copy
      6  1.1  christos  * in the file LICENSE in the source distribution or at
      7  1.1  christos  * https://www.openssl.org/source/license.html
      8  1.1  christos  */
      9  1.1  christos 
     10  1.1  christos #include <string.h>
     11  1.1  christos 
     12  1.1  christos #include "apps.h"
     13  1.1  christos #include "progs.h"
     14  1.1  christos #include <openssl/bio.h>
     15  1.1  christos #include <openssl/err.h>
     16  1.1  christos #include <openssl/evp.h>
     17  1.1  christos #include <openssl/kdf.h>
     18  1.1  christos #include <openssl/params.h>
     19  1.1  christos 
     20  1.1  christos typedef enum OPTION_choice {
     21  1.1  christos     OPT_COMMON,
     22  1.1  christos     OPT_KDFOPT, OPT_BIN, OPT_KEYLEN, OPT_OUT,
     23  1.1  christos     OPT_CIPHER, OPT_DIGEST, OPT_MAC,
     24  1.1  christos     OPT_PROV_ENUM
     25  1.1  christos } OPTION_CHOICE;
     26  1.1  christos 
     27  1.1  christos const OPTIONS kdf_options[] = {
     28  1.1  christos     {OPT_HELP_STR, 1, '-', "Usage: %s [options] kdf_name\n"},
     29  1.1  christos 
     30  1.1  christos     OPT_SECTION("General"),
     31  1.1  christos     {"help", OPT_HELP, '-', "Display this summary"},
     32  1.1  christos     {"kdfopt", OPT_KDFOPT, 's', "KDF algorithm control parameters in n:v form"},
     33  1.1  christos     {"cipher", OPT_CIPHER, 's', "Cipher"},
     34  1.1  christos     {"digest", OPT_DIGEST, 's', "Digest"},
     35  1.1  christos     {"mac", OPT_MAC, 's', "MAC"},
     36  1.1  christos     {OPT_MORE_STR, 1, '-', "See 'Supported Controls' in the EVP_KDF_ docs\n"},
     37  1.1  christos     {"keylen", OPT_KEYLEN, 's', "The size of the output derived key"},
     38  1.1  christos 
     39  1.1  christos     OPT_SECTION("Output"),
     40  1.1  christos     {"out", OPT_OUT, '>', "Output to filename rather than stdout"},
     41  1.1  christos     {"binary", OPT_BIN, '-',
     42  1.1  christos         "Output in binary format (default is hexadecimal)"},
     43  1.1  christos 
     44  1.1  christos     OPT_PROV_OPTIONS,
     45  1.1  christos 
     46  1.1  christos     OPT_PARAMETERS(),
     47  1.1  christos     {"kdf_name", 0, 0, "Name of the KDF algorithm"},
     48  1.1  christos     {NULL}
     49  1.1  christos };
     50  1.1  christos 
     51  1.1  christos static char *alloc_kdf_algorithm_name(STACK_OF(OPENSSL_STRING) **optp,
     52  1.1  christos                                       const char *name, const char *arg)
     53  1.1  christos {
     54  1.1  christos     size_t len = strlen(name) + strlen(arg) + 2;
     55  1.1  christos     char *res;
     56  1.1  christos 
     57  1.1  christos     if (*optp == NULL)
     58  1.1  christos         *optp = sk_OPENSSL_STRING_new_null();
     59  1.1  christos     if (*optp == NULL)
     60  1.1  christos         return NULL;
     61  1.1  christos 
     62  1.1  christos     res = app_malloc(len, "algorithm name");
     63  1.1  christos     BIO_snprintf(res, len, "%s:%s", name, arg);
     64  1.1  christos     if (sk_OPENSSL_STRING_push(*optp, res))
     65  1.1  christos         return res;
     66  1.1  christos     OPENSSL_free(res);
     67  1.1  christos     return NULL;
     68  1.1  christos }
     69  1.1  christos 
     70  1.1  christos int kdf_main(int argc, char **argv)
     71  1.1  christos {
     72  1.1  christos     int ret = 1, out_bin = 0;
     73  1.1  christos     OPTION_CHOICE o;
     74  1.1  christos     STACK_OF(OPENSSL_STRING) *opts = NULL;
     75  1.1  christos     char *prog, *hexout = NULL;
     76  1.1  christos     const char *outfile = NULL;
     77  1.1  christos     unsigned char *dkm_bytes = NULL;
     78  1.1  christos     size_t dkm_len = 0;
     79  1.1  christos     BIO *out = NULL;
     80  1.1  christos     EVP_KDF *kdf = NULL;
     81  1.1  christos     EVP_KDF_CTX *ctx = NULL;
     82  1.1  christos     char *digest = NULL, *cipher = NULL, *mac = NULL;
     83  1.1  christos 
     84  1.1  christos     prog = opt_init(argc, argv, kdf_options);
     85  1.1  christos     while ((o = opt_next()) != OPT_EOF) {
     86  1.1  christos         switch (o) {
     87  1.1  christos         default:
     88  1.1  christos opthelp:
     89  1.1  christos             BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
     90  1.1  christos             goto err;
     91  1.1  christos         case OPT_HELP:
     92  1.1  christos             opt_help(kdf_options);
     93  1.1  christos             ret = 0;
     94  1.1  christos             goto err;
     95  1.1  christos         case OPT_BIN:
     96  1.1  christos             out_bin = 1;
     97  1.1  christos             break;
     98  1.1  christos         case OPT_KEYLEN:
     99  1.1  christos             dkm_len = (size_t)atoi(opt_arg());
    100  1.1  christos             break;
    101  1.1  christos         case OPT_OUT:
    102  1.1  christos             outfile = opt_arg();
    103  1.1  christos             break;
    104  1.1  christos         case OPT_KDFOPT:
    105  1.1  christos             if (opts == NULL)
    106  1.1  christos                 opts = sk_OPENSSL_STRING_new_null();
    107  1.1  christos             if (opts == NULL || !sk_OPENSSL_STRING_push(opts, opt_arg()))
    108  1.1  christos                 goto opthelp;
    109  1.1  christos             break;
    110  1.1  christos         case OPT_CIPHER:
    111  1.1  christos             OPENSSL_free(cipher);
    112  1.1  christos             cipher = alloc_kdf_algorithm_name(&opts, "cipher", opt_arg());
    113  1.1  christos             if (cipher == NULL)
    114  1.1  christos                 goto opthelp;
    115  1.1  christos             break;
    116  1.1  christos         case OPT_DIGEST:
    117  1.1  christos             OPENSSL_free(digest);
    118  1.1  christos             digest = alloc_kdf_algorithm_name(&opts, "digest", opt_arg());
    119  1.1  christos             if (digest == NULL)
    120  1.1  christos                 goto opthelp;
    121  1.1  christos             break;
    122  1.1  christos         case OPT_MAC:
    123  1.1  christos             OPENSSL_free(mac);
    124  1.1  christos             mac = alloc_kdf_algorithm_name(&opts, "mac", opt_arg());
    125  1.1  christos             if (mac == NULL)
    126  1.1  christos                 goto opthelp;
    127  1.1  christos             break;
    128  1.1  christos         case OPT_PROV_CASES:
    129  1.1  christos             if (!opt_provider(o))
    130  1.1  christos                 goto err;
    131  1.1  christos             break;
    132  1.1  christos         }
    133  1.1  christos     }
    134  1.1  christos 
    135  1.1  christos     /* One argument, the KDF name. */
    136  1.1  christos     argc = opt_num_rest();
    137  1.1  christos     argv = opt_rest();
    138  1.1  christos     if (argc != 1)
    139  1.1  christos         goto opthelp;
    140  1.1  christos 
    141  1.1  christos     if ((kdf = EVP_KDF_fetch(app_get0_libctx(), argv[0],
    142  1.1  christos                              app_get0_propq())) == NULL) {
    143  1.1  christos         BIO_printf(bio_err, "Invalid KDF name %s\n", argv[0]);
    144  1.1  christos         goto opthelp;
    145  1.1  christos     }
    146  1.1  christos 
    147  1.1  christos     ctx = EVP_KDF_CTX_new(kdf);
    148  1.1  christos     if (ctx == NULL)
    149  1.1  christos         goto err;
    150  1.1  christos 
    151  1.1  christos     if (opts != NULL) {
    152  1.1  christos         int ok = 1;
    153  1.1  christos         OSSL_PARAM *params =
    154  1.1  christos             app_params_new_from_opts(opts, EVP_KDF_settable_ctx_params(kdf));
    155  1.1  christos 
    156  1.1  christos         if (params == NULL)
    157  1.1  christos             goto err;
    158  1.1  christos 
    159  1.1  christos         if (!EVP_KDF_CTX_set_params(ctx, params)) {
    160  1.1  christos             BIO_printf(bio_err, "KDF parameter error\n");
    161  1.1  christos             ERR_print_errors(bio_err);
    162  1.1  christos             ok = 0;
    163  1.1  christos         }
    164  1.1  christos         app_params_free(params);
    165  1.1  christos         if (!ok)
    166  1.1  christos             goto err;
    167  1.1  christos     }
    168  1.1  christos 
    169  1.1  christos     out = bio_open_default(outfile, 'w', out_bin ? FORMAT_BINARY : FORMAT_TEXT);
    170  1.1  christos     if (out == NULL)
    171  1.1  christos         goto err;
    172  1.1  christos 
    173  1.1  christos     if (dkm_len <= 0) {
    174  1.1  christos         BIO_printf(bio_err, "Invalid derived key length.\n");
    175  1.1  christos         goto err;
    176  1.1  christos     }
    177  1.1  christos     dkm_bytes = app_malloc(dkm_len, "out buffer");
    178  1.1  christos     if (dkm_bytes == NULL)
    179  1.1  christos         goto err;
    180  1.1  christos 
    181  1.1  christos     if (!EVP_KDF_derive(ctx, dkm_bytes, dkm_len, NULL)) {
    182  1.1  christos         BIO_printf(bio_err, "EVP_KDF_derive failed\n");
    183  1.1  christos         goto err;
    184  1.1  christos     }
    185  1.1  christos 
    186  1.1  christos     if (out_bin) {
    187  1.1  christos         BIO_write(out, dkm_bytes, dkm_len);
    188  1.1  christos     } else {
    189  1.1  christos         hexout = OPENSSL_buf2hexstr(dkm_bytes, dkm_len);
    190  1.1  christos         if (hexout == NULL) {
    191  1.1  christos             BIO_printf(bio_err, "Memory allocation failure\n");
    192  1.1  christos             goto err;
    193  1.1  christos         }
    194  1.1  christos         BIO_printf(out, "%s\n\n", hexout);
    195  1.1  christos     }
    196  1.1  christos 
    197  1.1  christos     ret = 0;
    198  1.1  christos err:
    199  1.1  christos     if (ret != 0)
    200  1.1  christos         ERR_print_errors(bio_err);
    201  1.1  christos     OPENSSL_clear_free(dkm_bytes, dkm_len);
    202  1.1  christos     sk_OPENSSL_STRING_free(opts);
    203  1.1  christos     EVP_KDF_free(kdf);
    204  1.1  christos     EVP_KDF_CTX_free(ctx);
    205  1.1  christos     BIO_free(out);
    206  1.1  christos     OPENSSL_free(hexout);
    207  1.1  christos     OPENSSL_free(cipher);
    208  1.1  christos     OPENSSL_free(digest);
    209  1.1  christos     OPENSSL_free(mac);
    210  1.1  christos     return ret;
    211  1.1  christos }
    212