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