8d11807f5f405089cc7ae24faeb2e3ea102fd23b
[oweals/openssl.git] / apps / kdf.c
1 /*
2  * Copyright 2019-2020 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/kdf.h>
18 #include <openssl/params.h>
19
20 DEFINE_STACK_OF_STRING()
21
22 typedef enum OPTION_choice {
23     OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
24     OPT_KDFOPT, OPT_BIN, OPT_KEYLEN, OPT_OUT,
25     OPT_PROV_ENUM
26 } OPTION_CHOICE;
27
28 const OPTIONS kdf_options[] = {
29     {OPT_HELP_STR, 1, '-', "Usage: %s [options] kdf_name\n"},
30
31     OPT_SECTION("General"),
32     {"help", OPT_HELP, '-', "Display this summary"},
33     {"kdfopt", OPT_KDFOPT, 's', "KDF algorithm control parameters in n:v form"},
34     {OPT_MORE_STR, 1, '-', "See 'Supported Controls' in the EVP_KDF_ docs\n"},
35     {"keylen", OPT_KEYLEN, 's', "The size of the output derived key"},
36
37     OPT_SECTION("Output"),
38     {"out", OPT_OUT, '>', "Output to filename rather than stdout"},
39     {"binary", OPT_BIN, '-',
40         "Output in binary format (default is hexadecimal)"},
41
42     OPT_PROV_OPTIONS,
43
44     OPT_PARAMETERS(),
45     {"kdf_name", 0, 0, "Name of the KDF algorithm"},
46     {NULL}
47 };
48
49 int kdf_main(int argc, char **argv)
50 {
51     int ret = 1, out_bin = 0;
52     OPTION_CHOICE o;
53     STACK_OF(OPENSSL_STRING) *opts = NULL;
54     char *prog, *hexout = NULL;
55     const char *outfile = NULL;
56     unsigned char *dkm_bytes = NULL;
57     size_t dkm_len = 0;
58     BIO *out = NULL;
59     EVP_KDF *kdf = NULL;
60     EVP_KDF_CTX *ctx = NULL;
61
62     prog = opt_init(argc, argv, kdf_options);
63     while ((o = opt_next()) != OPT_EOF) {
64         switch (o) {
65         default:
66 opthelp:
67             BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
68             goto err;
69         case OPT_HELP:
70             opt_help(kdf_options);
71             ret = 0;
72             goto err;
73         case OPT_BIN:
74             out_bin = 1;
75             break;
76         case OPT_KEYLEN:
77             dkm_len = (size_t)atoi(opt_arg());
78             break;
79         case OPT_OUT:
80             outfile = opt_arg();
81             break;
82         case OPT_KDFOPT:
83             if (opts == NULL)
84                 opts = sk_OPENSSL_STRING_new_null();
85             if (opts == NULL || !sk_OPENSSL_STRING_push(opts, opt_arg()))
86                 goto opthelp;
87             break;
88         case OPT_PROV_CASES:
89             if (!opt_provider(o))
90                 goto err;
91             break;
92         }
93     }
94     argc = opt_num_rest();
95     argv = opt_rest();
96
97     if (argc != 1) {
98         BIO_printf(bio_err, "Invalid number of extra arguments\n");
99         goto opthelp;
100     }
101
102     if ((kdf = EVP_KDF_fetch(NULL, argv[0], NULL)) == NULL) {
103         BIO_printf(bio_err, "Invalid KDF name %s\n", argv[0]);
104         goto opthelp;
105     }
106
107     ctx = EVP_KDF_CTX_new(kdf);
108     if (ctx == NULL)
109         goto err;
110
111     if (opts != NULL) {
112         int ok = 1;
113         OSSL_PARAM *params =
114             app_params_new_from_opts(opts, EVP_KDF_settable_ctx_params(kdf));
115
116         if (params == NULL)
117             goto err;
118
119         if (!EVP_KDF_CTX_set_params(ctx, params)) {
120             BIO_printf(bio_err, "KDF parameter error\n");
121             ERR_print_errors(bio_err);
122             ok = 0;
123         }
124         app_params_free(params);
125         if (!ok)
126             goto err;
127     }
128
129     out = bio_open_default(outfile, 'w', out_bin ? FORMAT_BINARY : FORMAT_TEXT);
130     if (out == NULL)
131         goto err;
132
133     if (dkm_len <= 0) {
134         BIO_printf(bio_err, "Invalid derived key length.\n");
135         goto err;
136     }
137     dkm_bytes = app_malloc(dkm_len, "out buffer");
138     if (dkm_bytes == NULL)
139         goto err;
140
141     if (!EVP_KDF_derive(ctx, dkm_bytes, dkm_len)) {
142         BIO_printf(bio_err, "EVP_KDF_derive failed\n");
143         goto err;
144     }
145
146     if (out_bin) {
147         BIO_write(out, dkm_bytes, dkm_len);
148     } else {
149         hexout = OPENSSL_buf2hexstr(dkm_bytes, dkm_len);
150         if (hexout == NULL) {
151             BIO_printf(bio_err, "Memory allocation failure\n");
152             goto err;
153         }
154         BIO_printf(out, "%s\n\n", hexout);
155     }
156
157     ret = 0;
158 err:
159     if (ret != 0)
160         ERR_print_errors(bio_err);
161     OPENSSL_clear_free(dkm_bytes, dkm_len);
162     sk_OPENSSL_STRING_free(opts);
163     EVP_KDF_free(kdf);
164     EVP_KDF_CTX_free(ctx);
165     BIO_free(out);
166     OPENSSL_free(hexout);
167     return ret;
168 }