]>
Commit | Line | Data |
---|---|---|
c54492ec SL |
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 | } |