Skip to content

Commit

Permalink
Opaque keys support for the openssl command line
Browse files Browse the repository at this point in the history
Support EVP_SKEY object for the `enc` command.
Support EVP_SKEYMGMT for the `list` command.
  • Loading branch information
beldmit committed Jan 20, 2025
1 parent ffd0014 commit a640100
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 9 deletions.
104 changes: 95 additions & 9 deletions apps/enc.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ typedef enum OPTION_choice {
OPT_NOPAD, OPT_SALT, OPT_NOSALT, OPT_DEBUG, OPT_UPPER_P, OPT_UPPER_A,
OPT_A, OPT_Z, OPT_BUFSIZE, OPT_K, OPT_KFILE, OPT_UPPER_K, OPT_NONE,
OPT_UPPER_S, OPT_IV, OPT_MD, OPT_ITER, OPT_PBKDF2, OPT_CIPHER,
OPT_SALTLEN, OPT_R_ENUM, OPT_PROV_ENUM
OPT_SALTLEN, OPT_R_ENUM, OPT_PROV_ENUM,
OPT_SKEYOPT, OPT_SKEYMGMT, OPT_GENKEY
} OPTION_CHOICE;

const OPTIONS enc_options[] = {
Expand Down Expand Up @@ -105,6 +106,9 @@ const OPTIONS enc_options[] = {
#ifndef OPENSSL_NO_ZLIB
{"z", OPT_Z, '-', "Compress or decompress encrypted data using zlib"},
#endif
{"skeyopt", OPT_SKEYOPT, 's', "Key options as opt:value for opaque keys handling"},
{"skeymgmt", OPT_SKEYMGMT, 's', "Symmetric key management name for opaque keys handling"},
{"genkey", OPT_GENKEY, '-', "Generate an opaque symmetric key"},
{"", OPT_CIPHER, '-', "Any supported cipher"},

OPT_R_OPTIONS,
Expand All @@ -130,10 +134,11 @@ int enc_main(int argc, char **argv)
char mbuf[sizeof(magic) - 1];
OPTION_CHOICE o;
int bsize = BSIZE, verbose = 0, debug = 0, olb64 = 0, nosalt = 0;
int enc = 1, printkey = 0, i, k;
int enc = 1, printkey = 0, genkey = 0, i, k;
int base64 = 0, informat = FORMAT_BINARY, outformat = FORMAT_BINARY;
int ret = 1, inl, nopad = 0;
unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
int rawkey_set = 0;
unsigned char *buff = NULL, salt[EVP_MAX_IV_LENGTH];
int saltlen = 0;
int pbkdf2 = 0;
Expand All @@ -150,6 +155,9 @@ int enc_main(int argc, char **argv)
BIO *bbrot = NULL;
int do_zstd = 0;
BIO *bzstd = NULL;
STACK_OF(OPENSSL_STRING) *skeyopts = NULL;
const char *skeymgmt = NULL;
EVP_SKEY *skey = NULL;

/* first check the command name */
if (strcmp(argv[0], "base64") == 0)
Expand Down Expand Up @@ -310,6 +318,19 @@ int enc_main(int argc, char **argv)
case OPT_NONE:
cipher = NULL;
break;
case OPT_SKEYOPT:
if ((skeyopts == NULL &&
(skeyopts = sk_OPENSSL_STRING_new_null()) == NULL) ||
sk_OPENSSL_STRING_push(skeyopts, opt_arg()) == 0) {
BIO_puts(bio_err, "out of memory\n");
goto end;
}
break;
case OPT_SKEYMGMT:
skeymgmt = opt_arg();
break;
case OPT_GENKEY:
genkey = 1;
case OPT_R_CASES:
if (!opt_rand(o))
goto end;
Expand Down Expand Up @@ -391,7 +412,7 @@ int enc_main(int argc, char **argv)
str = pass;
}

if ((str == NULL) && (cipher != NULL) && (hkey == NULL)) {
if ((str == NULL) && (cipher != NULL) && (hkey == NULL) && (skeyopts == NULL)) {
if (1) {
#ifndef OPENSSL_NO_UI_CONSOLE
for (;;) {
Expand Down Expand Up @@ -571,6 +592,7 @@ int enc_main(int argc, char **argv)
/* split and move data back to global buffer */
memcpy(key, tmpkeyiv, iklen);
memcpy(iv, tmpkeyiv+iklen, ivlen);
rawkey_set = 1;
} else {
BIO_printf(bio_err, "*** WARNING : "
"deprecated key derivation used.\n"
Expand All @@ -581,6 +603,7 @@ int enc_main(int argc, char **argv)
BIO_printf(bio_err, "EVP_BytesToKey failed\n");
goto end;
}
rawkey_set = 1;
}
/*
* zero the complete buffer or the string passed from the command
Expand Down Expand Up @@ -618,6 +641,18 @@ int enc_main(int argc, char **argv)
}
/* wiping secret data as we no longer need it */
cleanse(hkey);
rawkey_set = 1;
}

/*
* At this moment we should know whether we try to use raw bytes key
* (probably password-derived) or an opaque key.
* We should not allow both set of parameters at the same time
*/
if (rawkey_set > 0 && skeyopts != NULL) {
BIO_printf(bio_err, "You should use either raw key (probably password-derived) "
"or 'skeyopt' args.\n");
goto end;
}

if ((benc = BIO_new(BIO_f_cipher())) == NULL)
Expand All @@ -643,12 +678,36 @@ int enc_main(int argc, char **argv)
if (nopad)
EVP_CIPHER_CTX_set_padding(ctx, 0);

if (!EVP_CipherInit_ex(ctx, NULL, NULL, key,
(hiv == NULL && wrap == 1 ? NULL : iv), enc)) {
BIO_printf(bio_err, "Error setting cipher %s\n",
EVP_CIPHER_get0_name(cipher));
ERR_print_errors(bio_err);
goto end;
if (rawkey_set) {
if (!EVP_CipherInit_ex(ctx, NULL, NULL, key,
(hiv == NULL && wrap == 1 ? NULL : iv), enc)) {
BIO_printf(bio_err, "Error setting cipher %s\n",
EVP_CIPHER_get0_name(cipher));
ERR_print_errors(bio_err);
goto end;
}
} else {
OSSL_PARAM *params = app_params_new_from_opts(skeyopts,
EVP_CIPHER_CTX_settable_params(ctx));

skey = EVP_SKEY_import(app_get0_libctx(), skeymgmt ? skeymgmt : EVP_CIPHER_name(cipher),
app_get0_propq(), OSSL_SKEYMGMT_SELECT_ALL, params);
OSSL_PARAM_free(params);
if (skey == NULL) {
BIO_printf(bio_err, "Error creating opaque key object for skeymgmt %s\n",
skeymgmt ? skeymgmt : EVP_CIPHER_name(cipher));
ERR_print_errors(bio_err);
goto end;
}

if (!EVP_CipherInit_skey(ctx, NULL, skey,
(hiv == NULL && wrap == 1 ? NULL : iv),
EVP_CIPHER_get_iv_length(cipher), enc, NULL)) {
BIO_printf(bio_err, "Error setting an opaque key for cipher %s\n",
EVP_CIPHER_get0_name(cipher));
ERR_print_errors(bio_err);
goto end;
}
}

if (debug) {
Expand Down Expand Up @@ -680,6 +739,31 @@ int enc_main(int argc, char **argv)
goto end;
}
}

if (genkey) {
OSSL_PARAM *params = app_params_new_from_opts(skeyopts,
EVP_CIPHER_CTX_settable_params(ctx));

skey = EVP_SKEY_generate(app_get0_libctx(),
skeymgmt ? skeymgmt : EVP_CIPHER_name(cipher),
app_get0_propq(), params);
OSSL_PARAM_free(params);
if (skey == NULL) {
BIO_printf(bio_err, "Error creating opaque key for skeymgmt %s\n",
skeymgmt ? skeymgmt : EVP_CIPHER_name(cipher));
ERR_print_errors(bio_err);
} else {
char *key_name = EVP_SKEY_get1_key_id(skey);

BIO_printf(bio_out, "An opaque key identified by %s is created\n",
key_name ? key_name : "<unknown>");
BIO_printf(bio_out, "Provider: %s\n", EVP_SKEY_get0_provider_name(skey));
BIO_printf(bio_out, "Key management: %s\n", EVP_SKEY_get0_skeymgmt_name(skey));
OPENSSL_free(skey);
}

goto end;
}
}

/* Only encrypt/decrypt as we write the file */
Expand Down Expand Up @@ -716,6 +800,8 @@ int enc_main(int argc, char **argv)
}
end:
ERR_print_errors(bio_err);
sk_OPENSSL_STRING_free(skeyopts);
EVP_SKEY_free(skey);
OPENSSL_free(strbuf);
OPENSSL_free(buff);
BIO_free(in);
Expand Down
64 changes: 64 additions & 0 deletions apps/list.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ IS_FETCHABLE(mac, EVP_MAC)
IS_FETCHABLE(kdf, EVP_KDF)
IS_FETCHABLE(rand, EVP_RAND)
IS_FETCHABLE(keymgmt, EVP_KEYMGMT)
IS_FETCHABLE(skeymgmt, EVP_SKEYMGMT)
IS_FETCHABLE(signature, EVP_SIGNATURE)
IS_FETCHABLE(kem, EVP_KEM)
IS_FETCHABLE(asym_cipher, EVP_ASYM_CIPHER)
Expand Down Expand Up @@ -690,6 +691,61 @@ static void list_keymanagers(void)
sk_EVP_KEYMGMT_pop_free(km_stack, EVP_KEYMGMT_free);
}

DEFINE_STACK_OF(EVP_SKEYMGMT)
static int skeymanager_cmp(const EVP_SKEYMGMT * const *a,
const EVP_SKEYMGMT * const *b)
{
return strcmp(OSSL_PROVIDER_get0_name(EVP_SKEYMGMT_get0_provider(*a)),
OSSL_PROVIDER_get0_name(EVP_SKEYMGMT_get0_provider(*b)));
}

static void collect_skeymanagers(EVP_SKEYMGMT *km, void *stack)
{
STACK_OF(EVP_SKEYMGMT) *km_stack = stack;

if (is_skeymgmt_fetchable(km)
&& sk_EVP_SKEYMGMT_push(km_stack, km) > 0)
EVP_SKEYMGMT_up_ref(km);
}

static void list_skeymanagers(void)
{
int i;
STACK_OF(EVP_SKEYMGMT) *km_stack = sk_EVP_SKEYMGMT_new(skeymanager_cmp);

EVP_SKEYMGMT_do_all_provided(app_get0_libctx(), collect_skeymanagers,
km_stack);
sk_EVP_SKEYMGMT_sort(km_stack);

for (i = 0; i < sk_EVP_SKEYMGMT_num(km_stack); i++) {
EVP_SKEYMGMT *k = sk_EVP_SKEYMGMT_value(km_stack, i);
STACK_OF(OPENSSL_CSTRING) *names = NULL;

if (select_name != NULL && !EVP_SKEYMGMT_is_a(k, select_name))
continue;

names = sk_OPENSSL_CSTRING_new(name_cmp);
if (names != NULL && EVP_SKEYMGMT_names_do_all(k, collect_names, names)) {
const char *desc = EVP_SKEYMGMT_get0_description(k);

BIO_printf(bio_out, " Name: ");
if (desc != NULL)
BIO_printf(bio_out, "%s", desc);
else
BIO_printf(bio_out, "%s", sk_OPENSSL_CSTRING_value(names, 0));
BIO_printf(bio_out, "\n");
BIO_printf(bio_out, " Type: Provider Algorithm\n");
BIO_printf(bio_out, " IDs: ");
print_names(bio_out, names);
BIO_printf(bio_out, " @ %s\n",
OSSL_PROVIDER_get0_name(EVP_SKEYMGMT_get0_provider(k)));

}
sk_OPENSSL_CSTRING_free(names);
}
sk_EVP_SKEYMGMT_pop_free(km_stack, EVP_SKEYMGMT_free);
}

DEFINE_STACK_OF(EVP_SIGNATURE)
static int signature_cmp(const EVP_SIGNATURE * const *a,
const EVP_SIGNATURE * const *b)
Expand Down Expand Up @@ -1510,6 +1566,7 @@ typedef enum HELPLIST_CHOICE {
OPT_PK_ALGORITHMS, OPT_PK_METHOD, OPT_DISABLED,
OPT_KDF_ALGORITHMS, OPT_RANDOM_INSTANCES, OPT_RANDOM_GENERATORS,
OPT_ENCODERS, OPT_DECODERS, OPT_KEYMANAGERS, OPT_KEYEXCHANGE_ALGORITHMS,
OPT_SKEYMANAGERS,
OPT_KEM_ALGORITHMS, OPT_SIGNATURE_ALGORITHMS,
OPT_TLS_SIGNATURE_ALGORITHMS, OPT_ASYM_CIPHER_ALGORITHMS,
OPT_STORE_LOADERS, OPT_PROVIDER_INFO, OPT_OBJECTS,
Expand Down Expand Up @@ -1555,6 +1612,7 @@ const OPTIONS list_options[] = {
{"encoders", OPT_ENCODERS, '-', "List of encoding methods" },
{"decoders", OPT_DECODERS, '-', "List of decoding methods" },
{"key-managers", OPT_KEYMANAGERS, '-', "List of key managers" },
{"skey-managers", OPT_SKEYMANAGERS, '-', "List of symmetric key managers" },
{"key-exchange-algorithms", OPT_KEYEXCHANGE_ALGORITHMS, '-',
"List of key exchange algorithms" },
{"kem-algorithms", OPT_KEM_ALGORITHMS, '-',
Expand Down Expand Up @@ -1607,6 +1665,7 @@ int list_main(int argc, char **argv)
unsigned int encoder_algorithms:1;
unsigned int decoder_algorithms:1;
unsigned int keymanager_algorithms:1;
unsigned int skeymanager_algorithms:1;
unsigned int signature_algorithms:1;
unsigned int tls_signature_algorithms:1;
unsigned int keyexchange_algorithms:1;
Expand Down Expand Up @@ -1679,6 +1738,9 @@ int list_main(int argc, char **argv)
case OPT_KEYMANAGERS:
todo.keymanager_algorithms = 1;
break;
case OPT_SKEYMANAGERS:
todo.skeymanager_algorithms = 1;
break;
case OPT_SIGNATURE_ALGORITHMS:
todo.signature_algorithms = 1;
break;
Expand Down Expand Up @@ -1800,6 +1862,8 @@ int list_main(int argc, char **argv)
MAYBE_ADD_NL(list_decoders());
if (todo.keymanager_algorithms)
MAYBE_ADD_NL(list_keymanagers());
if (todo.skeymanager_algorithms)
MAYBE_ADD_NL(list_skeymanagers());
if (todo.signature_algorithms)
MAYBE_ADD_NL(list_signatures());
if (todo.tls_signature_algorithms)
Expand Down
28 changes: 28 additions & 0 deletions doc/man1/openssl-enc.pod.in
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ B<openssl> B<enc>|I<cipher>
[B<-v>]
[B<-debug>]
[B<-none>]
[B<-skeymgmt> I<skeymgmt>]
[B<-skeyopt> I<opt>:I<value>]
[B<-genkey>]
{- $OpenSSL::safe::opt_engine_synopsis -}{- $OpenSSL::safe::opt_r_synopsis -}
{- $OpenSSL::safe::opt_provider_synopsis -}

Expand Down Expand Up @@ -217,6 +220,25 @@ or zlib-dynamic option.

Use NULL cipher (no encryption or decryption of input).

=item B<-skeymgmt> I<skeymgmt>

Some providers may support opaque symmetric keys objects. To use them, the
particular we need to know the I<skeymgmt>. If not specified, the name of the
cipher will be used.

To find out the name of the suitable symmetric key management,
please refer C<openssl list -skey-managers> command output.

=item B<-skeyopt> I<opt>:I<value>

To obtain the existing opaque symmetric key or generate the new one, key
options are specified as opt:value. These options can't be used together with
any options implying raw key directly or indirectly.

=item B<-genkey>

Generate a new opaque key object.

{- $OpenSSL::safe::opt_r_item -}

{- $OpenSSL::safe::opt_provider_item -}
Expand Down Expand Up @@ -477,6 +499,10 @@ The B<openssl enc> command only supports a fixed number of algorithms with
certain parameters. So if, for example, you want to use RC2 with a
76 bit key or RC4 with an 84 bit key you can't use this program.

=head1 SEE ALSO

L<openssl-list(1)>, L<EVP_SKEY(3)>

=head1 HISTORY

The default digest was changed from MD5 to SHA256 in OpenSSL 1.1.0.
Expand All @@ -487,6 +513,8 @@ The B<-ciphers> and B<-engine> options were deprecated in OpenSSL 3.0.

The B<-saltlen> option was added in OpenSSL 3.2.

The B<-genkey>, B<-skeymgmt> and B<-skeyopt> options were added in OpenSSL 3.5.

=head1 COPYRIGHT

Copyright 2000-2024 The OpenSSL Project Authors. All Rights Reserved.
Expand Down
9 changes: 9 additions & 0 deletions doc/man1/openssl-list.pod.in
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ B<openssl list>
-}[B<-encoders>]
[B<-decoders>]
[B<-key-managers>]
[B<-skey-managers>]
[B<-key-exchange-algorithms>]
[B<-kem-algorithms>]
[B<-signature-algorithms>]
Expand Down Expand Up @@ -96,6 +97,8 @@ Display lists of all algorithms. These include:

=item Key managers

=item Symmetric key managers

=item Message authentication code algorithms (MAC)

=item Random number generators (RNG, DRBG)
Expand Down Expand Up @@ -183,6 +186,10 @@ Display a list of public key methods.

Display a list of key managers.

=item B<-skey-managers>

Display a list of symmetric key managers.

=item B<-key-exchange-algorithms>

Display a list of key exchange algorithms.
Expand Down Expand Up @@ -278,6 +285,8 @@ In both cases, C<bar> is the name of the provider.
The B<-engines>, B<-digest-commands>, and B<-cipher-commands> options
were deprecated in OpenSSL 3.0.

The B<-skey-managers> option was added in OpenSSL 3.5.

=head1 COPYRIGHT

Copyright 2016-2024 The OpenSSL Project Authors. All Rights Reserved.
Expand Down

0 comments on commit a640100

Please sign in to comment.