Implementing store support for EVP_SKEY

Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Simo Sorce <simo@redhat.com>
(Merged from https://github.com/openssl/openssl/pull/28278)
This commit is contained in:
Dmitry Belyavskiy
2025-08-11 11:55:06 +02:00
committed by Neil Horman
parent 1b035166bd
commit 1b0f21f055
22 changed files with 362 additions and 65 deletions

View File

@@ -75,7 +75,9 @@ typedef enum OPTION_choice {
OPT_R_ENUM,
OPT_PROV_ENUM,
OPT_SKEYOPT,
OPT_SKEYMGMT
OPT_SKEYMGMT,
OPT_SKEYURI,
OPT_PASSIN
} OPTION_CHOICE;
const OPTIONS enc_options[] = {
@@ -130,6 +132,8 @@ const OPTIONS enc_options[] = {
#endif
{ "skeyopt", OPT_SKEYOPT, 's', "Key options as opt:value for opaque symmetric key handling" },
{ "skeymgmt", OPT_SKEYMGMT, 's', "Symmetric key management name for opaque symmetric key handling" },
{ "skeyuri", OPT_SKEYURI, 's', "Symmetric key object URI" },
{ "storepass", OPT_PASSIN, 's', "Store pass phrase source when skeyuri is used (optional)" },
{ "", OPT_CIPHER, '-', "Any supported cipher" },
OPT_R_OPTIONS,
@@ -137,6 +141,33 @@ const OPTIONS enc_options[] = {
{ NULL }
};
static EVP_SKEY *skey_from_params(const EVP_CIPHER *cipher, const char *skeymgmt,
STACK_OF(OPENSSL_STRING) *opts)
{
EVP_SKEY *skey = NULL;
EVP_SKEYMGMT *mgmt = NULL;
OSSL_PARAM *params = NULL;
mgmt = EVP_SKEYMGMT_fetch(app_get0_libctx(),
skeymgmt != NULL ? skeymgmt : EVP_CIPHER_name(cipher),
app_get0_propq());
if (mgmt == NULL)
return NULL;
params = app_params_new_from_opts(opts, EVP_SKEYMGMT_get0_imp_settable_params(mgmt));
if (params == NULL) {
EVP_SKEYMGMT_free(mgmt);
return NULL;
}
skey = EVP_SKEY_import(app_get0_libctx(), EVP_SKEYMGMT_get0_name(mgmt),
app_get0_propq(), OSSL_SKEYMGMT_SELECT_ALL, params);
OSSL_PARAM_free(params);
EVP_SKEYMGMT_free(mgmt);
return skey;
}
int enc_main(int argc, char **argv)
{
static char buf[128];
@@ -149,6 +180,7 @@ int enc_main(int argc, char **argv)
char *hkey = NULL, *hiv = NULL, *hsalt = NULL, *p;
char *infile = NULL, *outfile = NULL, *prog;
char *str = NULL, *passarg = NULL, *pass = NULL, *strbuf = NULL;
char *storepassarg = NULL;
const char *ciphername = NULL;
char mbuf[sizeof(magic) - 1];
OPTION_CHOICE o;
@@ -176,8 +208,8 @@ int enc_main(int argc, char **argv)
BIO *bzstd = NULL;
STACK_OF(OPENSSL_STRING) *skeyopts = NULL;
const char *skeymgmt = NULL;
const char *skeyuri = NULL;
EVP_SKEY *skey = NULL;
EVP_SKEYMGMT *mgmt = NULL;
/* first check the command name */
if (strcmp(argv[0], "base64") == 0)
@@ -231,6 +263,9 @@ int enc_main(int argc, char **argv)
case OPT_PASS:
passarg = opt_arg();
break;
case OPT_PASSIN:
storepassarg = opt_arg();
break;
case OPT_D:
enc = 0;
break;
@@ -346,6 +381,9 @@ int enc_main(int argc, char **argv)
case OPT_SKEYMGMT:
skeymgmt = opt_arg();
break;
case OPT_SKEYURI:
skeyuri = opt_arg();
break;
case OPT_R_CASES:
if (!opt_rand(o))
goto end;
@@ -427,7 +465,8 @@ int enc_main(int argc, char **argv)
str = pass;
}
if ((str == NULL) && (cipher != NULL) && (hkey == NULL) && (skeyopts == NULL)) {
if ((str == NULL) && (cipher != NULL) && (hkey == NULL)
&& (skeyopts == NULL) && (skeyuri == NULL)) {
if (1) {
#ifndef OPENSSL_NO_UI_CONSOLE
for (;;) {
@@ -666,8 +705,8 @@ int enc_main(int argc, char **argv)
* At this moment we know whether we trying to use raw bytes as the key
* or an opaque symmetric key. We do not allow both options simultaneously.
*/
if (rawkey_set > 0 && skeyopts != NULL) {
BIO_printf(bio_err, "Either a raw key or the 'skeyopt' args must be used.\n");
if (rawkey_set > 0 && (skeyopts != NULL || skeyuri != NULL)) {
BIO_printf(bio_err, "Either a raw key or the skeyopt/skeyuri args must be used.\n");
goto end;
}
@@ -689,31 +728,35 @@ int enc_main(int argc, char **argv)
(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 = NULL;
char *storepass = NULL;
if (!app_passwd(storepassarg, NULL, &storepass, NULL)) {
BIO_printf(bio_err,
"Error getting store password from 'storepass' argument\n");
}
mgmt = EVP_SKEYMGMT_fetch(app_get0_libctx(),
skeymgmt != NULL ? skeymgmt : EVP_CIPHER_name(cipher),
app_get0_propq());
if (mgmt == NULL)
goto end;
params = app_params_new_from_opts(skeyopts,
EVP_SKEYMGMT_get0_imp_settable_params(mgmt));
if (params == NULL)
goto end;
skey = EVP_SKEY_import(app_get0_libctx(), EVP_SKEYMGMT_get0_name(mgmt),
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 (skeyuri != NULL) {
skey = load_skey(skeyuri, FORMAT_UNDEF, 0, storepass, 0);
OPENSSL_free(storepass);
if (skey == NULL) {
BIO_printf(bio_err, "Error loading opaque key object from URI %s\n", skeyuri);
goto end;
}
} else {
skey = skey_from_params(cipher, skeymgmt, skeyopts);
if (skey == NULL) {
BIO_printf(bio_err, "Error creating opaque key object for skeymgmt %s\n",
skeymgmt ? skeymgmt : EVP_CIPHER_name(cipher));
goto end;
}
}
if (!EVP_CipherInit_SKEY(ctx, cipher, skey,
@@ -721,7 +764,6 @@ int enc_main(int argc, char **argv)
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;
}
}
@@ -795,7 +837,6 @@ int enc_main(int argc, char **argv)
end:
ERR_print_errors(bio_err);
sk_OPENSSL_STRING_free(skeyopts);
EVP_SKEYMGMT_free(mgmt);
EVP_SKEY_free(skey);
OPENSSL_free(strbuf);
OPENSSL_free(buff);

View File

@@ -156,7 +156,10 @@ int load_key_certs_crls(const char *uri, int format, int maybe_stdin,
EVP_PKEY **ppkey, EVP_PKEY **ppubkey,
EVP_PKEY **pparams,
X509 **pcert, STACK_OF(X509) **pcerts,
X509_CRL **pcrl, STACK_OF(X509_CRL) **pcrls);
X509_CRL **pcrl, STACK_OF(X509_CRL) **pcrls.
EVP_SKEY **pskey);
EVP_SKEY *load_skey(const char *uri, int format, int maybe_stdin,
const char *pass, int quiet);
X509_STORE *setup_verify(const char *CAfile, int noCAfile,
const char *CApath, int noCApath,
const char *CAstore, int noCAstore);

View File

@@ -442,7 +442,7 @@ X509 *load_cert_pass(const char *uri, int format, int maybe_stdin,
}
} else {
(void)load_key_certs_crls(uri, format, maybe_stdin, pass, desc, 0,
NULL, NULL, NULL, &cert, NULL, NULL, NULL);
NULL, NULL, NULL, &cert, NULL, NULL, NULL, NULL);
}
return cert;
}
@@ -464,7 +464,7 @@ X509_CRL *load_crl(const char *uri, int format, int maybe_stdin,
}
} else {
(void)load_key_certs_crls(uri, format, maybe_stdin, NULL, desc, 0,
NULL, NULL, NULL, NULL, NULL, &crl, NULL);
NULL, NULL, NULL, NULL, NULL, &crl, NULL, NULL);
}
return crl;
}
@@ -555,7 +555,7 @@ EVP_PKEY *load_key(const char *uri, int format, int may_stdin,
desc = "private key";
(void)load_key_certs_crls(uri, format, may_stdin, pass, desc, 0,
&pkey, NULL, NULL, NULL, NULL, NULL, NULL);
&pkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
return pkey;
}
@@ -570,10 +570,10 @@ EVP_PKEY *load_pubkey(const char *uri, int format, int maybe_stdin,
desc = "public key";
(void)load_key_certs_crls(uri, format, maybe_stdin, pass, desc, 1,
NULL, &pkey, NULL, NULL, NULL, NULL, NULL);
NULL, &pkey, NULL, NULL, NULL, NULL, NULL, NULL);
if (pkey == NULL)
(void)load_key_certs_crls(uri, format, maybe_stdin, pass, desc, 0,
&pkey, NULL, NULL, NULL, NULL, NULL, NULL);
&pkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
return pkey;
}
@@ -587,7 +587,7 @@ EVP_PKEY *load_keyparams_suppress(const char *uri, int format, int maybe_stdin,
desc = "key parameters";
(void)load_key_certs_crls(uri, format, maybe_stdin, NULL, desc,
suppress_decode_errors,
NULL, NULL, &params, NULL, NULL, NULL, NULL);
NULL, NULL, &params, NULL, NULL, NULL, NULL, NULL);
if (params != NULL && keytype != NULL && !EVP_PKEY_is_a(params, keytype)) {
ERR_print_errors(bio_err);
BIO_printf(bio_err,
@@ -605,6 +605,17 @@ EVP_PKEY *load_keyparams(const char *uri, int format, int maybe_stdin,
return load_keyparams_suppress(uri, format, maybe_stdin, keytype, desc, 0);
}
EVP_SKEY *load_skey(const char *uri, int format, int may_stdin,
const char *pass, int quiet)
{
EVP_SKEY *skey = NULL;
(void)load_key_certs_crls(uri, format, may_stdin, pass, NULL, 0,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, &skey);
return skey;
}
void app_bail_out(char *fmt, ...)
{
va_list args;
@@ -704,7 +715,7 @@ int load_cert_certs(const char *uri,
}
pass_string = get_passwd(pass, desc);
ret = load_key_certs_crls(uri, FORMAT_UNDEF, 0, pass_string, desc, 0,
NULL, NULL, NULL, pcert, pcerts, NULL, NULL);
NULL, NULL, NULL, pcert, pcerts, NULL, NULL, NULL);
clear_free(pass_string);
if (ret) {
@@ -805,7 +816,7 @@ int load_certs(const char *uri, int maybe_stdin, STACK_OF(X509) **certs,
if (desc == NULL)
desc = "certificates";
return load_key_certs_crls(uri, FORMAT_UNDEF, maybe_stdin, pass, desc, 0,
NULL, NULL, NULL, NULL, certs, NULL, NULL);
NULL, NULL, NULL, NULL, certs, NULL, NULL, NULL);
}
/*
@@ -818,7 +829,7 @@ int load_crls(const char *uri, STACK_OF(X509_CRL) **crls,
if (desc == NULL)
desc = "CRLs";
return load_key_certs_crls(uri, FORMAT_UNDEF, 0, pass, desc, 0,
NULL, NULL, NULL, NULL, NULL, NULL, crls);
NULL, NULL, NULL, NULL, NULL, NULL, crls, NULL);
}
static const char *format2string(int format)
@@ -845,20 +856,21 @@ static const char *format2string(int format)
SET_EXPECT(val); \
}
/* Provide (error msg) text for some of the credential types to be loaded. */
#define FAIL_NAME \
(ppkey != NULL ? "private key" : ppubkey != NULL ? "public key" \
: pparams != NULL ? "key parameters" \
: pcert != NULL ? "certificate" \
: pcerts != NULL ? "certificates" \
: pcrl != NULL ? "CRL" \
: pcrls != NULL ? "CRLs" \
#define FAIL_NAME \
(ppkey != NULL ? "private key" : ppubkey != NULL ? "public key" \
: pparams != NULL ? "key parameters" \
: pcert != NULL ? "certificate" \
: pcerts != NULL ? "certificates" \
: pcrl != NULL ? "CRL" \
: pcrls != NULL ? "CRLs" \
: pskey != NULL ? "symmetric key" : NULL \
: NULL)
/*
* Load those types of credentials for which the result pointer is not NULL.
* Reads from stdin if 'uri' is NULL and 'maybe_stdin' is nonzero.
* 'format' parameter may be FORMAT_PEM, FORMAT_ASN1, or 0 for no hint.
* desc may contain more detail on the credential(s) to be loaded for error msg
* For non-NULL ppkey, pcert, and pcrl the first suitable value found is loaded.
* For non-NULL ppkey, pcert, pcrl, and pskey the first suitable value found is loaded.
* If pcerts is non-NULL and *pcerts == NULL then a new cert list is allocated.
* If pcerts is non-NULL then all available certificates are appended to *pcerts
* except any certificate assigned to *pcert.
@@ -867,18 +879,20 @@ static const char *format2string(int format)
* except any CRL assigned to *pcrl.
* On error, any contents of non-NULL credential pointers are freed.
*/
int load_key_certs_crls(const char *uri, int format, int maybe_stdin,
const char *pass, const char *desc, int quiet,
EVP_PKEY **ppkey, EVP_PKEY **ppubkey,
EVP_PKEY **pparams,
X509 **pcert, STACK_OF(X509) **pcerts,
X509_CRL **pcrl, STACK_OF(X509_CRL) **pcrls)
X509_CRL **pcrl, STACK_OF(X509_CRL) **pcrls,
EVP_SKEY **pskey)
{
PW_CB_DATA uidata;
OSSL_STORE_CTX *ctx = NULL;
OSSL_LIB_CTX *libctx = app_get0_libctx();
const char *propq = app_get0_propq();
int ncerts = 0, ncrls = 0, expect = -1;
int ncerts = 0, ncrls = 0, nskeys = 0, expect = -1;
const char *failed = FAIL_NAME;
const char *input_type;
OSSL_PARAM itp[2];
@@ -898,9 +912,10 @@ int load_key_certs_crls(const char *uri, int format, int maybe_stdin,
SET_EXPECT1(ppubkey, OSSL_STORE_INFO_PUBKEY);
SET_EXPECT1(pparams, OSSL_STORE_INFO_PARAMS);
SET_EXPECT1(pcert, OSSL_STORE_INFO_CERT);
SET_EXPECT1(pskey, OSSL_STORE_INFO_SKEY);
/*
* Up to here, the following holds.
* If just one of the ppkey, ppubkey, pparams, and pcert function parameters
* If just one of the ppkey, ppubkey, pparams, pcert, and pskey function parameters
* is nonzero, expect > 0 indicates which type of credential is expected.
* If expect == 0, more than one of them is nonzero (multiple types expected).
*/
@@ -969,6 +984,7 @@ int load_key_certs_crls(const char *uri, int format, int maybe_stdin,
BIO_printf(bio_err, "Could not open file or uri for loading");
goto end;
}
/* expect == 0 means here multiple types of credentials are to be loaded */
if (expect > 0 && !OSSL_STORE_expect(ctx, expect)) {
if (!quiet)
@@ -980,7 +996,8 @@ int load_key_certs_crls(const char *uri, int format, int maybe_stdin,
/* from here, failed != NULL only if actually an error has been detected */
while ((ppkey != NULL || ppubkey != NULL || pparams != NULL
|| pcert != NULL || pcerts != NULL || pcrl != NULL || pcrls != NULL)
|| pcert != NULL || pcerts != NULL || pcrl != NULL || pcrls != NULL
|| pskey != NULL)
&& !OSSL_STORE_eof(ctx)) {
OSSL_STORE_INFO *info = OSSL_STORE_load(ctx);
int type, ok = 1;
@@ -1047,6 +1064,14 @@ int load_key_certs_crls(const char *uri, int format, int maybe_stdin,
}
ncrls += ok;
break;
case OSSL_STORE_INFO_SKEY:
if (pskey != NULL) {
ok = (*pskey = OSSL_STORE_INFO_get1_SKEY(info)) != NULL;
if (ok)
pskey = NULL;
}
nskeys += ok;
break;
default:
/* skip any other type; ok stays == 1 */
break;
@@ -1069,6 +1094,8 @@ end:
pcerts = NULL;
if (ncrls > 0)
pcrls = NULL;
if (nskeys > 0)
pskey = NULL;
failed = FAIL_NAME;
if (failed != NULL && !quiet)
BIO_printf(bio_err, "Could not find");

View File

@@ -33,6 +33,7 @@ typedef enum OPTION_choice {
OPT_SEARCHFOR_CERTS,
OPT_SEARCHFOR_KEYS,
OPT_SEARCHFOR_CRLS,
OPT_SEARCHFOR_SKEYS,
OPT_CRITERION_SUBJECT,
OPT_CRITERION_ISSUER,
OPT_CRITERION_SERIAL,
@@ -53,6 +54,7 @@ const OPTIONS storeutl_options[] = {
{ "certs", OPT_SEARCHFOR_CERTS, '-', "Search for certificates only" },
{ "keys", OPT_SEARCHFOR_KEYS, '-', "Search for keys only" },
{ "crls", OPT_SEARCHFOR_CRLS, '-', "Search for CRLs only" },
{ "skeys", OPT_SEARCHFOR_SKEYS, '-', "Search for symmetric keys only" },
{ "subject", OPT_CRITERION_SUBJECT, 's', "Search by subject" },
{ "issuer", OPT_CRITERION_ISSUER, 's', "Search by issuer and serial, issuer name" },
{ "serial", OPT_CRITERION_SERIAL, 's', "Search by issuer and serial, serial number" },
@@ -124,6 +126,7 @@ int storeutl_main(int argc, char *argv[])
case OPT_SEARCHFOR_CERTS:
case OPT_SEARCHFOR_KEYS:
case OPT_SEARCHFOR_CRLS:
case OPT_SEARCHFOR_SKEYS:
if (expected != 0) {
BIO_printf(bio_err, "%s: only one search type can be given.\n",
prog);
@@ -137,6 +140,7 @@ int storeutl_main(int argc, char *argv[])
{ OPT_SEARCHFOR_CERTS, OSSL_STORE_INFO_CERT },
{ OPT_SEARCHFOR_KEYS, OSSL_STORE_INFO_PKEY },
{ OPT_SEARCHFOR_CRLS, OSSL_STORE_INFO_CRL },
{ OPT_SEARCHFOR_SKEYS, OSSL_STORE_INFO_SKEY },
};
size_t i;
@@ -476,6 +480,9 @@ static int process(const char *uri, const UI_METHOD *uimeth, PW_CB_DATA *uidata,
if (!noout)
PEM_write_bio_X509_CRL(out, OSSL_STORE_INFO_get0_CRL(info));
break;
case OSSL_STORE_INFO_SKEY:
/* Currently there is no universal API allowing to print smth, so no output */
break;
default:
BIO_printf(bio_err, "!!! Unknown code\n");
ret++;

View File

@@ -898,6 +898,7 @@ OSSL_STORE_R_NOT_A_CRL:101:not a crl
OSSL_STORE_R_NOT_A_NAME:103:not a name
OSSL_STORE_R_NOT_A_PRIVATE_KEY:102:not a private key
OSSL_STORE_R_NOT_A_PUBLIC_KEY:122:not a public key
OSSL_STORE_R_NOT_A_SYMMETRIC_KEY:124:not a symmetric key
OSSL_STORE_R_NOT_PARAMETERS:104:not parameters
OSSL_STORE_R_NO_LOADERS_FOUND:123:no loaders found
OSSL_STORE_R_PASSPHRASE_CALLBACK_ERROR:114:passphrase callback error

View File

@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
@@ -38,6 +38,8 @@ static const ERR_STRING_DATA OSSL_STORE_str_reasons[] = {
"not a private key" },
{ ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_NOT_A_PUBLIC_KEY),
"not a public key" },
{ ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_NOT_A_SYMMETRIC_KEY),
"not a symmetric key" },
{ ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_NOT_PARAMETERS),
"not parameters" },
{ ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_NO_LOADERS_FOUND),

View File

@@ -295,7 +295,7 @@ int OSSL_STORE_expect(OSSL_STORE_CTX *ctx, int expected_type)
int ret = 1;
if (ctx == NULL
|| expected_type < 0 || expected_type > OSSL_STORE_INFO_CRL) {
|| expected_type < 0 || expected_type > OSSL_STORE_INFO_SKEY) {
ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
@@ -690,6 +690,15 @@ OSSL_STORE_INFO *OSSL_STORE_INFO_new_CRL(X509_CRL *crl)
return info;
}
OSSL_STORE_INFO *OSSL_STORE_INFO_new_SKEY(EVP_SKEY *skey)
{
OSSL_STORE_INFO *info = OSSL_STORE_INFO_new(OSSL_STORE_INFO_SKEY, skey);
if (info == NULL)
ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_OSSL_STORE_LIB);
return info;
}
/*
* Functions to try to extract data from an OSSL_STORE_INFO.
*/
@@ -825,6 +834,24 @@ X509_CRL *OSSL_STORE_INFO_get1_CRL(const OSSL_STORE_INFO *info)
return NULL;
}
EVP_SKEY *OSSL_STORE_INFO_get0_SKEY(const OSSL_STORE_INFO *info)
{
if (info->type == OSSL_STORE_INFO_SKEY)
return info->_.skey;
return NULL;
}
EVP_SKEY *OSSL_STORE_INFO_get1_SKEY(const OSSL_STORE_INFO *info)
{
if (info->type == OSSL_STORE_INFO_SKEY) {
if (!EVP_SKEY_up_ref(info->_.skey))
return NULL;
return info->_.skey;
}
ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_SYMMETRIC_KEY);
return NULL;
}
/*
* Free the OSSL_STORE_INFO
*/
@@ -851,6 +878,9 @@ void OSSL_STORE_INFO_free(OSSL_STORE_INFO *info)
case OSSL_STORE_INFO_CRL:
X509_CRL_free(info->_.crl);
break;
case OSSL_STORE_INFO_SKEY:
EVP_SKEY_free(info->_.skey);
break;
}
OPENSSL_free(info);
}

View File

@@ -37,6 +37,7 @@ struct ossl_store_info_st {
EVP_PKEY *pkey; /* when type == OSSL_STORE_INFO_PKEY */
X509 *x509; /* when type == OSSL_STORE_INFO_CERT */
X509_CRL *crl; /* when type == OSSL_STORE_INFO_CRL */
EVP_SKEY *skey; /* when type == OSSL_STORE_INFO_SKEY */
} _;
};
DEFINE_STACK_OF(OSSL_STORE_INFO)

View File

@@ -83,6 +83,8 @@ static int try_crl(struct extracted_param_data_st *, OSSL_STORE_INFO **,
OSSL_LIB_CTX *, const char *);
static int try_pkcs12(struct extracted_param_data_st *, OSSL_STORE_INFO **,
OSSL_STORE_CTX *, OSSL_LIB_CTX *, const char *);
static int try_skey(struct extracted_param_data_st *, OSSL_STORE_INFO **,
const OSSL_PROVIDER *, OSSL_LIB_CTX *, const char *);
int ossl_store_handle_load_result(const OSSL_PARAM params[], void *arg)
{
@@ -150,6 +152,10 @@ int ossl_store_handle_load_result(const OSSL_PARAM params[], void *arg)
if (*v == NULL && !try_pkcs12(&helper_data, v, ctx, libctx, propq))
goto err;
ERR_pop_to_mark();
ERR_set_mark();
if (*v == NULL && !try_skey(&helper_data, v, provider, libctx, propq))
goto err;
ERR_pop_to_mark();
if (*v == NULL) {
const char *hint = "";
@@ -665,3 +671,49 @@ static int try_pkcs12(struct extracted_param_data_st *data, OSSL_STORE_INFO **v,
return ok;
}
static int try_skey(struct extracted_param_data_st *data, OSSL_STORE_INFO **v,
const OSSL_PROVIDER *provider, OSSL_LIB_CTX *libctx, const char *propq)
{
EVP_SKEY *skey = NULL;
const char *skeymgmt_name = data->data_type == NULL
? OSSL_SKEY_TYPE_GENERIC : data->data_type;
size_t keysize = 0;
unsigned char *keybytes = NULL;
if (data->object_type != OSSL_OBJECT_SKEY)
return 0;
if (data->octet_data != NULL) {
keysize = data->octet_data_size;
keybytes = (unsigned char *)data->octet_data;
skey = EVP_SKEY_import_raw_key(libctx, skeymgmt_name,
keybytes, keysize, propq);
} else if (data->ref != NULL) {
EVP_SKEYMGMT *skeymgmt = evp_skeymgmt_fetch_from_prov((OSSL_PROVIDER *)provider,
skeymgmt_name, propq);
OSSL_PARAM params[2];
/*
* We got an internal reference from a particular provider so we need the SKEYMGMT
* exactly from this provider
*/
if (skeymgmt == NULL)
return 0;
keysize = data->ref_size;
keybytes = (unsigned char *)data->ref;
params[0] = OSSL_PARAM_construct_octet_ptr(OSSL_OBJECT_PARAM_REFERENCE,
(void **)&keybytes, keysize);
params[1] = OSSL_PARAM_construct_end();
skey = EVP_SKEY_import_SKEYMGMT(libctx, skeymgmt, OSSL_SKEYMGMT_SELECT_ALL, params);
}
if (skey != NULL)
*v = OSSL_STORE_INFO_new_SKEY(skey);
if (*v == NULL)
EVP_SKEY_free(skey);
return 1;
}

View File

@@ -17,7 +17,8 @@ static const char *const type_strings[] = {
"Public key", /* OSSL_STORE_INFO_PUBKEY */
"Pkey", /* OSSL_STORE_INFO_PKEY */
"Certificate", /* OSSL_STORE_INFO_CERT */
"CRL" /* OSSL_STORE_INFO_CRL */
"CRL", /* OSSL_STORE_INFO_CRL */
"Symmetric key" /* OSSL_STORE_INFO_SKEY */
};
const char *OSSL_STORE_INFO_type_string(int type)

View File

@@ -41,6 +41,8 @@ B<openssl> B<enc>|I<cipher>
[B<-none>]
[B<-skeymgmt> I<skeymgmt>]
[B<-skeyopt> I<opt>:I<value>]
[B<-skeyuri> I<uri>]
[B<-storepass> I<arg>]
{- $OpenSSL::safe::opt_r_synopsis -}
{- $OpenSSL::safe::opt_provider_synopsis -}
@@ -237,6 +239,18 @@ To obtain an existing opaque symmetric key or generate a 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<-skeyuri> I<uri>
The URI identifying the symmetric key object to be used for encryption. This
option can't be used together with any options implying raw key directly or
indirectly. The B<-skeymgmt> option is ignored. If both B<-skeyuri> and
B<-skeyopt> options are provided, B<-skeyuri> is ignored.
=item B<-storepass> I<arg>
The input URI password source. For more information about the format of I<arg>
see L<openssl-passphrase-options(1)>.
{- $OpenSSL::safe::opt_r_item -}
{- $OpenSSL::safe::opt_provider_item -}
@@ -485,7 +499,7 @@ certain parameters. So if, for example, you want to use RC2 with a
=head1 SEE ALSO
L<openssl-list(1)>, L<EVP_SKEY(3)>
L<openssl-list(1)>, L<EVP_SKEY(3)>, L<openssl-passphrase-options(1)>
=head1 HISTORY
@@ -501,6 +515,8 @@ The B<-skeymgmt> and B<-skeyopt> options were added in OpenSSL 3.5.
The B<-engine> option was removed in OpenSSL 4.0.
The B<-skeyuri> and B<-storepass> options were added in OpenSSL 4.0.
=head1 COPYRIGHT
Copyright 2000-2025 The OpenSSL Project Authors. All Rights Reserved.

View File

@@ -21,6 +21,7 @@ B<openssl> B<storeutl>
[B<-certs>]
[B<-keys>]
[B<-crls>]
[B<-skeys>]
[B<-subject> I<arg>]
[B<-issuer> I<arg>]
[B<-serial> I<arg>]
@@ -75,7 +76,9 @@ Fetch objects recursively when possible.
=item B<-crls>
Only select the certificates, keys or CRLs from the given URI.
=item B<-skeys>
Only select the certificates, keys, CRLs or symmetric keys from the given URI.
However, if this URI would return a set of names (URIs), those are always
returned.
@@ -138,9 +141,11 @@ This command was added in OpenSSL 1.1.1.
The B<-engine> option was removed in OpenSSL 4.0.
The B<-skeys> option was added in OpenSSL 4.0
=head1 COPYRIGHT
Copyright 2016-2024 The OpenSSL Project Authors. All Rights Reserved.
Copyright 2016-2025 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy

View File

@@ -6,14 +6,16 @@ OSSL_STORE_INFO, OSSL_STORE_INFO_get_type, OSSL_STORE_INFO_get0_NAME,
OSSL_STORE_INFO_get0_NAME_description,
OSSL_STORE_INFO_get0_PARAMS, OSSL_STORE_INFO_get0_PUBKEY,
OSSL_STORE_INFO_get0_PKEY, OSSL_STORE_INFO_get0_CERT, OSSL_STORE_INFO_get0_CRL,
OSSL_STORE_INFO_get0_SKEY,
OSSL_STORE_INFO_get1_NAME, OSSL_STORE_INFO_get1_NAME_description,
OSSL_STORE_INFO_get1_PARAMS, OSSL_STORE_INFO_get1_PUBKEY,
OSSL_STORE_INFO_get1_PKEY, OSSL_STORE_INFO_get1_CERT, OSSL_STORE_INFO_get1_CRL,
OSSL_STORE_INFO_get1_SKEY,
OSSL_STORE_INFO_type_string, OSSL_STORE_INFO_free,
OSSL_STORE_INFO_new_NAME, OSSL_STORE_INFO_set0_NAME_description,
OSSL_STORE_INFO_new_PARAMS, OSSL_STORE_INFO_new_PUBKEY,
OSSL_STORE_INFO_new_PKEY, OSSL_STORE_INFO_new_CERT, OSSL_STORE_INFO_new_CRL,
OSSL_STORE_INFO_new, OSSL_STORE_INFO_get0_data
OSSL_STORE_INFO_new, OSSL_STORE_INFO_new_SKEY, OSSL_STORE_INFO_get0_data
- Functions to manipulate OSSL_STORE_INFO objects
=head1 SYNOPSIS
@@ -38,6 +40,8 @@ OSSL_STORE_INFO_new, OSSL_STORE_INFO_get0_data
X509 *OSSL_STORE_INFO_get1_CERT(const OSSL_STORE_INFO *store_info);
X509_CRL *OSSL_STORE_INFO_get0_CRL(const OSSL_STORE_INFO *store_info);
X509_CRL *OSSL_STORE_INFO_get1_CRL(const OSSL_STORE_INFO *store_info);
EVP_SKEY *OSSL_STORE_INFO_get0_SKEY(const OSSL_STORE_INFO *store_info);
EVP_SKEY *OSSL_STORE_INFO_get1_SKEY(const OSSL_STORE_INFO *store_info);
const char *OSSL_STORE_INFO_type_string(int type);
@@ -50,6 +54,7 @@ OSSL_STORE_INFO_new, OSSL_STORE_INFO_get0_data
OSSL_STORE_INFO *OSSL_STORE_INFO_new_PKEY(EVP_PKEY *pkey);
OSSL_STORE_INFO *OSSL_STORE_INFO_new_CERT(X509 *x509);
OSSL_STORE_INFO *OSSL_STORE_INFO_new_CRL(X509_CRL *crl);
OSSL_STORE_INFO *OSSL_STORE_INFO_new_SKEY(EVP_SKEY *skey);
OSSL_STORE_INFO *OSSL_STORE_INFO_new(int type, void *data);
void *OSSL_STORE_INFO_get0_data(int type, const OSSL_STORE_INFO *info);
@@ -87,7 +92,7 @@ short string describing it.
OSSL_STORE_INFO_get0_NAME(), OSSL_STORE_INFO_get0_NAME_description(),
OSSL_STORE_INFO_get0_PARAMS(), OSSL_STORE_INFO_get0_PUBKEY(),
OSSL_STORE_INFO_get0_PKEY(), OSSL_STORE_INFO_get0_CERT(),
OSSL_STORE_INFO_get0_CRL()
OSSL_STORE_INFO_get0_CRL(), OSSL_STORE_INFO_get0_SKEY()
all take a B<OSSL_STORE_INFO> and return the object it holds if the
B<OSSL_STORE_INFO> type (as returned by OSSL_STORE_INFO_get_type())
matches the function, otherwise NULL.
@@ -95,7 +100,7 @@ matches the function, otherwise NULL.
OSSL_STORE_INFO_get1_NAME(), OSSL_STORE_INFO_get1_NAME_description(),
OSSL_STORE_INFO_get1_PARAMS(), OSSL_STORE_INFO_get1_PUBKEY(),
OSSL_STORE_INFO_get1_PKEY(), OSSL_STORE_INFO_get1_CERT() and
OSSL_STORE_INFO_get1_CRL()
OSSL_STORE_INFO_get1_CRL(), OSSL_STORE_INFO_get1_SKEY()
all take a B<OSSL_STORE_INFO> and return a duplicate the object it
holds if the B<OSSL_STORE_INFO> type (as returned by
OSSL_STORE_INFO_get_type()) matches the function, otherwise NULL.
@@ -105,7 +110,8 @@ If the argument is NULL, nothing is done.
OSSL_STORE_INFO_new_NAME() , OSSL_STORE_INFO_new_PARAMS(),
, OSSL_STORE_INFO_new_PUBKEY(), OSSL_STORE_INFO_new_PKEY(),
OSSL_STORE_INFO_new_CERT() and OSSL_STORE_INFO_new_CRL()
OSSL_STORE_INFO_new_CERT(), OSSL_STORE_INFO_new_CRL() and
OSSL_STORE_INFO_new_SKEY()
create a B<OSSL_STORE_INFO> object to hold the given input object.
On success the input object is consumed.
@@ -181,6 +187,10 @@ An X.509 certificate.
A X.509 certificate revocation list.
=item OSSL_STORE_INFO_SKEY
A symmetric key object.
=back
=head1 RETURN VALUES
@@ -191,21 +201,23 @@ There is no error value.
OSSL_STORE_INFO_get0_NAME(), OSSL_STORE_INFO_get0_NAME_description(),
OSSL_STORE_INFO_get0_PARAMS(), OSSL_STORE_INFO_get0_PKEY(),
OSSL_STORE_INFO_get0_CERT() and OSSL_STORE_INFO_get0_CRL() all return
a pointer to the OpenSSL object on success, NULL otherwise.
OSSL_STORE_INFO_get0_CERT(), OSSL_STORE_INFO_get0_CRL() and
OSSL_STORE_INFO_get0_SKEY() all return a pointer to the OpenSSL object on
success, NULL otherwise.
OSSL_STORE_INFO_get1_NAME(), OSSL_STORE_INFO_get1_NAME_description(),
OSSL_STORE_INFO_get1_PARAMS(), OSSL_STORE_INFO_get1_PKEY(),
OSSL_STORE_INFO_get1_CERT() and OSSL_STORE_INFO_get1_CRL() all return
a pointer to a duplicate of the OpenSSL object on success, NULL otherwise.
OSSL_STORE_INFO_get1_CERT(), OSSL_STORE_INFO_get1_CRL() and
OSSL_STORE_INFO_get1_SKEY() all return a pointer to a duplicate of the OpenSSL
object on success, NULL otherwise.
OSSL_STORE_INFO_type_string() returns a string on success, or NULL on
failure.
OSSL_STORE_INFO_new_NAME(), OSSL_STORE_INFO_new_PARAMS(),
OSSL_STORE_INFO_new_PKEY(), OSSL_STORE_INFO_new_CERT() and
OSSL_STORE_INFO_new_CRL() return a B<OSSL_STORE_INFO>
pointer on success, or NULL on failure.
OSSL_STORE_INFO_new_PKEY(), OSSL_STORE_INFO_new_CERT(),
OSSL_STORE_INFO_new_CRL() and OSSL_STORE_INFO_new_SKEY() return a
B<OSSL_STORE_INFO> pointer on success, or NULL on failure.
OSSL_STORE_INFO_set0_NAME_description() returns 1 on success, or 0 on
failure.
@@ -220,6 +232,9 @@ The OSSL_STORE API was added in OpenSSL 1.1.1.
The OSSL_STORE_INFO_PUBKEY object type was added in OpenSSL 3.0.
OSSL_STORE_INFO_get0_SKEY(), OSSL_STORE_INFO_get1_SKEY() and
OSSL_STORE_INFO_new_SKEY() were added in OpenSSL 4.0.
=head1 COPYRIGHT
Copyright 2016-2024 The OpenSSL Project Authors. All Rights Reserved.

View File

@@ -35,6 +35,13 @@ If the file isn't determined to be formatted as PEM, the content is
loaded in raw form in its entirety and passed to the available file
handlers as is, with no PEM name or headers.
Store 'file' also supports load of symmetric keys from arbitrary files. As
symmetric keys don't have any structure and encapsulation, the interpretation
of a file as a symmetric key should be requested explicitly via
L<OSSL_STORE_expect(3)>.
When loading from a file, symmetric keys are limited to 2048 bytes in length.
Each file handler is expected to handle PEM and non-PEM content as
appropriate. Some may refuse non-PEM content for the sake of
determinism (for example, there are keys out in the wild that are
@@ -57,11 +64,15 @@ See L<passphrase-encoding(7)> for more information.
=head1 SEE ALSO
L<ossl_store(7)>, L<passphrase-encoding(7)>
L<ossl_store(7)>, L<passphrase-encoding(7)>, L<OSSL_STORE_expect(3)>
=head1 HISTORY
Support for reading symmetric keys from files was added in OpenSSL 4.0
=head1 COPYRIGHT
Copyright 2018 The OpenSSL Project Authors. All Rights Reserved.
Copyright 2018-2025 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy

View File

@@ -29,6 +29,7 @@ extern "C" {
#define OSSL_OBJECT_PKEY 2 /* EVP_PKEY * */
#define OSSL_OBJECT_CERT 3 /* X509 * */
#define OSSL_OBJECT_CRL 4 /* X509_CRL * */
#define OSSL_OBJECT_SKEY 5 /* EVP_SKEY * */
/*
* The rest of the associated OSSL_PARAM elements is described in core_names.h

View File

@@ -160,6 +160,7 @@ OSSL_STORE_CTX *OSSL_STORE_attach(BIO *bio, const char *scheme,
#define OSSL_STORE_INFO_PKEY 4 /* EVP_PKEY * */
#define OSSL_STORE_INFO_CERT 5 /* X509 * */
#define OSSL_STORE_INFO_CRL 6 /* X509_CRL * */
#define OSSL_STORE_INFO_SKEY 7 /* EVP_SKEY * */
/*
* Functions to generate OSSL_STORE_INFOs, one function for each type we
@@ -176,6 +177,7 @@ OSSL_STORE_INFO *OSSL_STORE_INFO_new_PUBKEY(EVP_PKEY *pubkey);
OSSL_STORE_INFO *OSSL_STORE_INFO_new_PKEY(EVP_PKEY *pkey);
OSSL_STORE_INFO *OSSL_STORE_INFO_new_CERT(X509 *x509);
OSSL_STORE_INFO *OSSL_STORE_INFO_new_CRL(X509_CRL *crl);
OSSL_STORE_INFO *OSSL_STORE_INFO_new_SKEY(EVP_SKEY *skey);
/*
* Functions to try to extract data from a OSSL_STORE_INFO.
@@ -196,6 +198,8 @@ X509 *OSSL_STORE_INFO_get0_CERT(const OSSL_STORE_INFO *info);
X509 *OSSL_STORE_INFO_get1_CERT(const OSSL_STORE_INFO *info);
X509_CRL *OSSL_STORE_INFO_get0_CRL(const OSSL_STORE_INFO *info);
X509_CRL *OSSL_STORE_INFO_get1_CRL(const OSSL_STORE_INFO *info);
EVP_SKEY *OSSL_STORE_INFO_get0_SKEY(const OSSL_STORE_INFO *info);
EVP_SKEY *OSSL_STORE_INFO_get1_SKEY(const OSSL_STORE_INFO *info);
const char *OSSL_STORE_INFO_type_string(int type);

View File

@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
@@ -32,6 +32,7 @@
#define OSSL_STORE_R_NOT_A_NAME 103
#define OSSL_STORE_R_NOT_A_PRIVATE_KEY 102
#define OSSL_STORE_R_NOT_A_PUBLIC_KEY 122
#define OSSL_STORE_R_NOT_A_SYMMETRIC_KEY 124
#define OSSL_STORE_R_NOT_PARAMETERS 104
#define OSSL_STORE_R_NO_LOADERS_FOUND 123
#define OSSL_STORE_R_PASSPHRASE_CALLBACK_ERROR 114

View File

@@ -464,6 +464,8 @@ static int file_setup_decoders(struct file_ctx_st *ctx)
goto err;
}
break;
case OSSL_STORE_INFO_SKEY: /* No input structure */
break;
default:
break;
}
@@ -502,6 +504,16 @@ static int file_setup_decoders(struct file_ctx_st *ctx)
continue;
}
/*
* As any sequence of bytes can be a secret key, we allow
* reading raw key from a file only when it is explicitly requested.
*/
if ((ctx->expected_type != OSSL_STORE_INFO_SKEY)
&& OPENSSL_strcasecmp(input_type, "raw") == 0) {
ossl_decoder_instance_free(to_obj_inst);
continue;
}
if (!ossl_decoder_ctx_add_decoder_inst(ctx->_.file.decoderctx,
to_obj_inst)) {
ossl_decoder_instance_free(to_obj_inst);

View File

@@ -302,14 +302,66 @@ err:
OSSL_DISPATCH_END \
}
#define MAX_RAW_KEY_SIZE 2048
static OSSL_FUNC_decoder_decode_fn raw2obj_decode;
static int raw2obj_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
OSSL_CALLBACK *data_cb, void *data_cbarg,
OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
{
struct any2obj_ctx_st *ctx = vctx;
BIO *in = ossl_bio_new_from_core_bio(ctx->provctx, cin);
BUF_MEM *mem = NULL;
size_t len = 0, max_len = MAX_RAW_KEY_SIZE;
int ok = 0;
if (in == NULL)
goto err;
if ((mem = BUF_MEM_new()) == NULL
|| BUF_MEM_grow(mem, max_len) == 0) {
ERR_raise(ERR_LIB_PEM, ERR_R_BUF_LIB);
goto err;
}
ok = BIO_read_ex(in, &mem->data[0], max_len, &len);
if (ok == 0) {
ERR_raise(ERR_LIB_BIO, ERR_R_BIO_LIB);
goto err;
}
if (len == 0) {
ERR_raise(ERR_LIB_PEM, ERR_R_UNSUPPORTED);
goto err;
}
BIO_free(in);
if (BUF_MEM_grow(mem, len) != len) {
ERR_raise(ERR_LIB_PEM, ERR_R_BUF_LIB);
goto err;
}
/* any2obj_decode_final() frees |mem| for us */
return any2obj_decode_final(ctx, OSSL_OBJECT_SKEY, "raw", "SKEY",
mem, data_cb, data_cbarg);
err:
BIO_free(in);
BUF_MEM_free(mem);
return 0;
}
MAKE_DECODER(der, OSSL_OBJECT_UNKNOWN);
MAKE_DECODER(msblob, OSSL_OBJECT_PKEY);
MAKE_DECODER(pvk, OSSL_OBJECT_PKEY);
MAKE_DECODER(raw, OSSL_OBJECT_SKEY);
const OSSL_ALGORITHM ossl_any_to_obj_algorithm[] = {
{ "obj", "input=DER", der_to_obj_decoder_functions },
{ "obj", "input=MSBLOB", msblob_to_obj_decoder_functions },
{ "obj", "input=PVK", pvk_to_obj_decoder_functions },
{ "obj", "input=RAW", raw_to_obj_decoder_functions },
{
NULL,
}

View File

@@ -41,7 +41,7 @@ my @ciphers =
|rc2|rc4|seed)/x} @ciphers
if disabled("legacy");
plan tests => 5 + (scalar @ciphers)*2;
plan tests => 6 + (scalar @ciphers)*2;
SKIP: {
skip "Problems getting ciphers...", 1 + scalar(@ciphers)
@@ -90,4 +90,16 @@ plan tests => 5 + (scalar @ciphers)*2;
&& compare_text($test,"salted.clear") == 0,
"Check that we can still use a salt length of 16 bytes for PKDF2");
#./util/wrap.pl apps/openssl enc -aes128 -K 30313032303330343035303630373038 -iv 100f0e0d0c0b0a090807060504030201 -in 1.txt -out 2.enc
#./util/wrap.pl apps/openssl enc -aes128 -skeyuri skeyfile.bin -iv 100f0e0d0c0b0a090807060504030201 -in 1.txt -out 1.enc
my $folder = "test/recipes/20-test_enc_data";
my $skeyuri = srctop_file($folder, "skeyfile.bin");
ok(run(app([$cmd, "enc", "-in", $test, "-aes128", "-K", "30313032303330343035303630373038",
"-iv", "100f0e0d0c0b0a090807060504030201",
"-out", "key_from_cmdline.enc"]))
&& run(app([$cmd, "enc", "-in", $test, "-aes128", "-skeyuri", $skeyuri,
"-iv", "100f0e0d0c0b0a090807060504030201",
"-out", "key_from_uri.enc" ]))
&& File::Compare::compare("key_from_cmdline.enc", "key_from_uri.enc") == 0,
"Check that key from URI gives an equal result comparing to the explicit one");
}

Binary file not shown.

View File

@@ -5805,6 +5805,9 @@ i2d_OSSL_AA_DIST_POINT ? 4_0_0 EXIST::FUNCTION:
OSSL_AA_DIST_POINT_free ? 4_0_0 EXIST::FUNCTION:
OSSL_AA_DIST_POINT_new ? 4_0_0 EXIST::FUNCTION:
OSSL_AA_DIST_POINT_it ? 4_0_0 EXIST::FUNCTION:
OSSL_STORE_INFO_new_SKEY ? 4_0_0 EXIST::FUNCTION:
OSSL_STORE_INFO_get0_SKEY ? 4_0_0 EXIST::FUNCTION:
OSSL_STORE_INFO_get1_SKEY ? 4_0_0 EXIST::FUNCTION:
OPENSSL_posix_to_tm ? 4_0_0 EXIST::FUNCTION:
OPENSSL_tm_to_posix ? 4_0_0 EXIST::FUNCTION:
OPENSSL_timegm ? 4_0_0 EXIST::FUNCTION: