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