diff options
-rw-r--r-- | crypto/err/err.c | 1 | ||||
-rw-r--r-- | crypto/err/openssl.txt | 1 | ||||
-rw-r--r-- | crypto/serializer/build.info | 3 | ||||
-rw-r--r-- | crypto/serializer/serializer_err.c | 31 | ||||
-rw-r--r-- | crypto/serializer/serializer_local.h | 9 | ||||
-rw-r--r-- | crypto/serializer/serializer_meth.c | 2 | ||||
-rw-r--r-- | crypto/serializer/serializer_pkey.c | 386 | ||||
-rw-r--r-- | doc/man3/OSSL_SERIALIZER.pod | 2 | ||||
-rw-r--r-- | doc/man3/OSSL_SERIALIZER_CTX_new_by_EVP_PKEY.pod | 134 | ||||
-rw-r--r-- | doc/man7/provider-serializer.pod | 49 | ||||
-rw-r--r-- | include/openssl/core_names.h | 11 | ||||
-rw-r--r-- | include/openssl/err.h | 1 | ||||
-rw-r--r-- | include/openssl/serializer.h | 35 | ||||
-rw-r--r-- | include/openssl/serializererr.h | 34 | ||||
-rw-r--r-- | util/libcrypto.num | 6 | ||||
-rw-r--r-- | util/missingcrypto.txt | 1 | ||||
-rw-r--r-- | util/other.syms | 6 |
17 files changed, 710 insertions, 2 deletions
diff --git a/crypto/err/err.c b/crypto/err/err.c index 0fb46bef4d..e77cfe83cf 100644 --- a/crypto/err/err.c +++ b/crypto/err/err.c @@ -113,6 +113,7 @@ static ERR_STRING_DATA ERR_str_reasons[] = { {ERR_R_INIT_FAIL, "init fail"}, {ERR_R_OPERATION_FAIL, "operation fail"}, {ERR_R_INVALID_PROVIDER_FUNCTIONS, "invalid provider functions"}, + {ERR_R_INTERRUPTED_OR_CANCELLED, "interrupted or cancelled"}, {0, NULL}, }; diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index b103f8605b..8febc5c210 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -2550,6 +2550,7 @@ OCSP_R_STATUS_TOO_OLD:127:status too old OCSP_R_UNKNOWN_MESSAGE_DIGEST:119:unknown message digest OCSP_R_UNKNOWN_NID:120:unknown nid OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE:129:unsupported requestorname type +OSSL_SERIALIZER_R_INCORRECT_PROPERTY_QUERY:100:incorrect property query OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE:107:ambiguous content type OSSL_STORE_R_BAD_PASSWORD_READ:115:bad password read OSSL_STORE_R_ERROR_VERIFYING_PKCS12_MAC:113:error verifying pkcs12 mac diff --git a/crypto/serializer/build.info b/crypto/serializer/build.info index 1a35152586..551319ed59 100644 --- a/crypto/serializer/build.info +++ b/crypto/serializer/build.info @@ -1 +1,2 @@ -SOURCE[../../libcrypto]=serializer_meth.c serializer_lib.c +SOURCE[../../libcrypto]=serializer_meth.c serializer_lib.c serializer_pkey.c \ + serializer_err.c diff --git a/crypto/serializer/serializer_err.c b/crypto/serializer/serializer_err.c new file mode 100644 index 0000000000..0f0fc5fa80 --- /dev/null +++ b/crypto/serializer/serializer_err.c @@ -0,0 +1,31 @@ +/* + * Generated by util/mkerr.pl DO NOT EDIT + * Copyright 1995-2019 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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/err.h> +#include <openssl/serializererr.h> + +#ifndef OPENSSL_NO_ERR + +static const ERR_STRING_DATA OSSL_SERIALIZER_str_reasons[] = { + {ERR_PACK(ERR_LIB_OSSL_SERIALIZER, 0, OSSL_SERIALIZER_R_INCORRECT_PROPERTY_QUERY), + "incorrect property query"}, + {0, NULL} +}; + +#endif + +int ERR_load_OSSL_SERIALIZER_strings(void) +{ +#ifndef OPENSSL_NO_ERR + if (ERR_reason_error_string(OSSL_SERIALIZER_str_reasons[0].error) == NULL) + ERR_load_strings_const(OSSL_SERIALIZER_str_reasons); +#endif + return 1; +} diff --git a/crypto/serializer/serializer_local.h b/crypto/serializer/serializer_local.h index dd0eb85414..9ee0eb8244 100644 --- a/crypto/serializer/serializer_local.h +++ b/crypto/serializer/serializer_local.h @@ -38,4 +38,13 @@ struct ossl_serializer_ctx_st { */ const void *object; int (*do_output)(OSSL_SERIALIZER_CTX *ctx, BIO *out); + + /* For any function that needs a passphrase reader */ + const UI_METHOD *ui_method; + void *ui_data; + /* + * if caller used OSSL_SERIALIZER_CTX_set_passphrase_cb(), we need + * intermediary storage. + */ + UI_METHOD *allocated_ui_method; }; diff --git a/crypto/serializer/serializer_meth.c b/crypto/serializer/serializer_meth.c index 103188f93a..145d58921f 100644 --- a/crypto/serializer/serializer_meth.c +++ b/crypto/serializer/serializer_meth.c @@ -10,6 +10,7 @@ #include <openssl/core.h> #include <openssl/core_numbers.h> #include <openssl/serializer.h> +#include <openssl/ui.h> #include "internal/core.h" #include "internal/namemap.h" #include "internal/property.h" @@ -509,6 +510,7 @@ void OSSL_SERIALIZER_CTX_free(OSSL_SERIALIZER_CTX *ctx) if (ctx->ser != NULL && ctx->ser->freectx != NULL) ctx->ser->freectx(ctx->serctx); OSSL_SERIALIZER_free(ctx->ser); + UI_destroy_method(ctx->allocated_ui_method); OPENSSL_free(ctx); } } diff --git a/crypto/serializer/serializer_pkey.c b/crypto/serializer/serializer_pkey.c new file mode 100644 index 0000000000..d3c3362f66 --- /dev/null +++ b/crypto/serializer/serializer_pkey.c @@ -0,0 +1,386 @@ +/* + * Copyright 2019 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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/err.h> +#include <openssl/ui.h> +#include <openssl/params.h> +#include <openssl/serializer.h> +#include <openssl/core_names.h> +#include "internal/provider.h" +#include "internal/property.h" +#include "crypto/evp.h" +#include "serializer_local.h" + +int OSSL_SERIALIZER_CTX_set_cipher(OSSL_SERIALIZER_CTX *ctx, + const char *cipher_name, + const char *propquery) +{ + OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END }; + + params[0] = + OSSL_PARAM_construct_utf8_string(OSSL_SERIALIZER_PARAM_CIPHER, + (void *)cipher_name, 0); + params[1] = + OSSL_PARAM_construct_utf8_string(OSSL_SERIALIZER_PARAM_PROPERTIES, + (void *)propquery, 0); + + return OSSL_SERIALIZER_CTX_set_params(ctx, params); +} + +int OSSL_SERIALIZER_CTX_set_passphrase(OSSL_SERIALIZER_CTX *ctx, + const unsigned char *kstr, + size_t klen) +{ + OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END }; + + params[0] = OSSL_PARAM_construct_octet_string(OSSL_SERIALIZER_PARAM_PASS, + (void *)kstr, klen); + + return OSSL_SERIALIZER_CTX_set_params(ctx, params); +} + +static void serializer_ctx_reset_passphrase_ui(OSSL_SERIALIZER_CTX *ctx) +{ + UI_destroy_method(ctx->allocated_ui_method); + ctx->allocated_ui_method = NULL; + ctx->ui_method = NULL; + ctx->ui_data = NULL; +} + +int OSSL_SERIALIZER_CTX_set_passphrase_ui(OSSL_SERIALIZER_CTX *ctx, + const UI_METHOD *ui_method, + void *ui_data) +{ + if (!ossl_assert(ctx != NULL)) { + ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + serializer_ctx_reset_passphrase_ui(ctx); + ctx->ui_method = ui_method; + ctx->ui_data = ui_data; + return 1; +} + +int OSSL_SERIALIZER_CTX_set_passphrase_cb(OSSL_SERIALIZER_CTX *ctx, int enc, + pem_password_cb *cb, void *cbarg) +{ + if (!ossl_assert(ctx != NULL)) { + ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + serializer_ctx_reset_passphrase_ui(ctx); + if (cb == NULL) + return 1; + ctx->ui_method = + ctx->allocated_ui_method = UI_UTIL_wrap_read_pem_callback(cb, enc); + ctx->ui_data = cbarg; + + return ctx->ui_method != NULL; +} + +/* + * Support for OSSL_SERIALIZER_CTX_new_by_TYPE: + * finding a suitable serializer + */ + +struct selected_serializer_st { + OPENSSL_CTX *libctx; + const OSSL_PROVIDER *desired_provider; + const char *propquery; + + /* + * When selecting serializers, we need to check the intended use. + * This is governed by the |domainparams| flag in the EVP_PKEY, + * we must just make sure to filter on 'type=domainparams' accordingly. + */ + int want_domainparams; + + /* + * Serializers offer two functions, one that handles object data in + * the form of a OSSL_PARAM array, and one that directly handles a + * provider side object. The latter requires that the serializer + * is offered by the same provider that holds that object, but is + * more desirable because it usually provides faster serialization. + * + * When looking up possible serializers, we save the first that can + * handle an OSSL_PARAM array in |first|, and the first that can + * handle a provider side object in |desired|. + */ + OSSL_SERIALIZER *first; + OSSL_SERIALIZER *desired; +}; + +static void select_serializer(const char *name, void *data) +{ + struct selected_serializer_st *d = data; + OSSL_SERIALIZER *s = NULL; + OSSL_PROPERTY_LIST *check = + d->want_domainparams + ? ossl_parse_query(d->libctx, "type=domainparams") + : NULL; + + /* No need to look further if we already have the more desirable option */ + if (d->desired != NULL) + return; + + if ((s = OSSL_SERIALIZER_fetch(d->libctx, name, d->propquery)) != NULL) { + /* + * Extra check if domain parameters are explicitly specified: + * only accept serializers that have the "type=domainparams" + * property. + * + * For data that isn't marked as domain parameters, a domain + * parameters serializer is still acceptable, because a key + * may hold domain parameters too. + */ + if (d->want_domainparams) { + OSSL_PROPERTY_LIST *current_props = + ossl_parse_property(d->libctx, OSSL_SERIALIZER_properties(s)); + int check_cnt = ossl_property_match_count(check, current_props); + + if (check_cnt == 0) { + OSSL_SERIALIZER_free(s); + return; + } + } + + if (d->first == NULL && s->serialize_data != NULL) { + d->first = s; + } else if (OSSL_SERIALIZER_provider(s) == d->desired_provider + && s->serialize_object != NULL) { + OSSL_SERIALIZER_free(d->first); + d->first = NULL; + d->desired = s; + } else { + OSSL_SERIALIZER_free(s); + } + } +} + +/* + * Support for OSSL_SERIALIZER_CTX_new_by_TYPE and OSSL_SERIALIZER_to_bio: + * Passphrase callbacks + */ + +/* + * First, we define the generic passphrase function that supports both + * outgoing (with passphrase verify) and incoming (without passphrase verify) + * passphrase reading. + */ +static int serializer_passphrase(char *pass, size_t pass_size, + size_t *pass_len, int verify, + const OSSL_PARAM params[], void *arg) +{ + OSSL_SERIALIZER_CTX *ctx = arg; + const OSSL_PARAM *p; + const char *prompt_info = NULL; + char *prompt = NULL, *vpass = NULL; + int prompt_idx = -1, verify_idx = -1; + UI *ui = NULL; + int ret = 0; + + if (!ossl_assert(ctx != NULL && pass != NULL + && pass_size != 0 && pass_len != NULL)) { + ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if ((p = OSSL_PARAM_locate_const(params, + OSSL_PASSPHRASE_PARAM_INFO)) != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + prompt_info = p->data; + } + + if ((ui = UI_new()) == NULL) { + ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_MALLOC_FAILURE); + return 0; + } + + UI_set_method(ui, ctx->ui_method); + UI_add_user_data(ui, ctx->ui_data); + + /* Get an application constructed prompt */ + prompt = UI_construct_prompt(ui, "pass phrase", prompt_info); + if (prompt == NULL) { + ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_MALLOC_FAILURE); + goto end; + } + + prompt_idx = UI_add_input_string(ui, prompt, + UI_INPUT_FLAG_DEFAULT_PWD, + pass, 0, pass_size - 1) - 1; + if (prompt_idx < 0) { + ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_UI_LIB); + goto end; + } + + if (verify) { + /* Get a buffer for verification prompt */ + vpass = OPENSSL_zalloc(pass_size); + if (vpass == NULL) { + ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_MALLOC_FAILURE); + goto end; + } + verify_idx = UI_add_verify_string(ui, prompt, + UI_INPUT_FLAG_DEFAULT_PWD, + vpass, 0, pass_size - 1, + pass) - 1; + if (verify_idx < 0) { + ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_UI_LIB); + goto end; + } + } + + switch (UI_process(ui)) { + case -2: + ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_INTERRUPTED_OR_CANCELLED); + break; + case -1: + ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_UI_LIB); + break; + default: + *pass_len = (size_t)UI_get_result_length(ui, prompt_idx); + ret = 1; + break; + } + + end: + OPENSSL_free(vpass); + OPENSSL_free(prompt); + UI_free(ui); + return ret; +} + +/* Ensure correct function definition for outgoing passphrase reader */ +static OSSL_PASSPHRASE_CALLBACK serializer_passphrase_out_cb; +static int serializer_passphrase_out_cb(char *pass, size_t pass_size, + size_t *pass_len, + const OSSL_PARAM params[], void *arg) +{ + return serializer_passphrase(pass, pass_size, pass_len, 1, params, arg); +} + +/* + * Support for OSSL_SERIALIZER_to_bio: + * writing callback for the OSSL_PARAM (the implementation doesn't have + * intimate knowledge of the provider side object) + */ + +struct serializer_write_data_st { + OSSL_SERIALIZER_CTX *ctx; + BIO *out; +}; + +static int serializer_write_cb(const OSSL_PARAM params[], void *arg) +{ + struct serializer_write_data_st *write_data = arg; + OSSL_SERIALIZER_CTX *ctx = write_data->ctx; + BIO *out = write_data->out; + + return ctx->ser->serialize_data(ctx->serctx, params, out, + serializer_passphrase_out_cb, ctx); +} + +/* + * Support for OSSL_SERIALIZER_to_bio: + * Perform the actual output. + */ + +static int serializer_EVP_PKEY_to_bio(OSSL_SERIALIZER_CTX *ctx, BIO *out) +{ + const EVP_PKEY *pkey = ctx->object; + void *provdata = pkey->pkeys[0].provdata; + int domainparams = pkey->pkeys[0].domainparams; + EVP_KEYMGMT *keymgmt = pkey->pkeys[0].keymgmt; + + /* + * OSSL_SERIALIZER_CTX_new() creates a context, even when the + * serializer it's given is NULL. Callers can detect the lack + * of serializer with OSSL_SERIALIZER_CTX_get_serializer() and + * should take precautions, possibly call a fallback instead of + * OSSL_SERIALIZER_to_bio() / OSSL_SERIALIZER_to_fp(). If it's + * come this far, we return an error. + */ + if (ctx->ser == NULL) + return 0; + + if (ctx->ser->serialize_object == NULL) { + struct serializer_write_data_st write_data; + + write_data.ctx = ctx; + write_data.out = out; + + if (domainparams) + return evp_keymgmt_exportdomparams(keymgmt, provdata, + serializer_write_cb, + &write_data); + return evp_keymgmt_exportkey(keymgmt, provdata, + serializer_write_cb, &write_data); + } + + return ctx->ser->serialize_object(ctx->serctx, provdata, out, + serializer_passphrase_out_cb, ctx); +} + +/* + * OSSL_SERIALIZER_CTX_new_by_EVP_PKEY() returns a ctx with no serializer if + * it couldn't find a suitable serializer. This allows a caller to detect if + * a suitable serializer was found, with OSSL_SERIALIZER_CTX_get_serializer(), + * and to use fallback methods if the result is NULL. + */ +OSSL_SERIALIZER_CTX *OSSL_SERIALIZER_CTX_new_by_EVP_PKEY(const EVP_PKEY *pkey, + const char *propquery) +{ + OSSL_SERIALIZER_CTX *ctx = NULL; + OSSL_SERIALIZER *ser = NULL; + EVP_KEYMGMT *keymgmt = pkey->pkeys[0].keymgmt; + + if (!ossl_assert(pkey != NULL && propquery != NULL)) { + ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + + if (keymgmt != NULL) { + const OSSL_PROVIDER *desired_prov = EVP_KEYMGMT_provider(keymgmt); + OPENSSL_CTX *libctx = ossl_provider_library_context(desired_prov); + struct selected_serializer_st sel_data; + + memset(&sel_data, 0, sizeof(sel_data)); + sel_data.libctx = libctx; + sel_data.desired_provider = desired_prov; + sel_data.propquery = propquery; + sel_data.want_domainparams = pkey->pkeys[0].domainparams; + EVP_KEYMGMT_names_do_all(keymgmt, select_serializer, &sel_data); + + if (sel_data.desired != NULL) { + ser = sel_data.desired; + sel_data.desired = NULL; + } else if (sel_data.first != NULL) { + ser = sel_data.first; + sel_data.first = NULL; + } + OSSL_SERIALIZER_free(sel_data.first); + OSSL_SERIALIZER_free(sel_data.desired); + } + + ctx = OSSL_SERIALIZER_CTX_new(ser); /* refcnt(ser)++ */ + OSSL_SERIALIZER_free(ser); /* refcnt(ser)-- */ + + if (ctx != NULL) { + /* Setup for OSSL_SERIALIZE_to_bio() */ + ctx->object = pkey; + ctx->do_output = serializer_EVP_PKEY_to_bio; + } + + return ctx; +} + diff --git a/doc/man3/OSSL_SERIALIZER.pod b/doc/man3/OSSL_SERIALIZER.pod index bf6ef3431c..05b889bf60 100644 --- a/doc/man3/OSSL_SERIALIZER.pod +++ b/doc/man3/OSSL_SERIALIZER.pod @@ -111,7 +111,7 @@ OSSL_SERIALIZER_number() returns an integer. =head1 SEE ALSO L<provider(7)>, L<OSSL_SERIALIZER_CTX(3)>, L<OSSL_SERIALIZER_to_bio(3)>, -L<OPENSSL_CTX(3)> +L<OSSL_SERIALIZER_CTX_new_by_EVP_PKEY(3)>, L<OPENSSL_CTX(3)> =head1 HISTORY diff --git a/doc/man3/OSSL_SERIALIZER_CTX_new_by_EVP_PKEY.pod b/doc/man3/OSSL_SERIALIZER_CTX_new_by_EVP_PKEY.pod new file mode 100644 index 0000000000..caa9294bcc --- /dev/null +++ b/doc/man3/OSSL_SERIALIZER_CTX_new_by_EVP_PKEY.pod @@ -0,0 +1,134 @@ +=pod + +=head1 NAME + +OSSL_SERIALIZER_CTX_new_by_EVP_PKEY, +OSSL_SERIALIZER_CTX_set_cipher, +OSSL_SERIALIZER_CTX_set_passphrase, +OSSL_SERIALIZER_CTX_set_passphrase_cb, +OSSL_SERIALIZER_CTX_set_passphrase_ui, +OSSL_SERIALIZER_PUBKEY_TO_PEM_PQ, +OSSL_SERIALIZER_PrivateKey_TO_PEM_PQ, +OSSL_SERIALIZER_Parameters_TO_PEM_PQ, +OSSL_SERIALIZER_PUBKEY_TO_TEXT_PQ, +OSSL_SERIALIZER_PrivateKey_TO_TEXT_PQ, +OSSL_SERIALIZER_Parameters_TO_TEXT_PQ +- Serializer routines to serialize EVP_PKEYs + +=head1 SYNOPSIS + + #include <openssl/serializer.h> + + OSSL_SERIALIZER_CTX *OSSL_SERIALIZER_CTX_new_by_EVP_PKEY(const EVP_PKEY *pkey, + const char *propquery); + + int OSSL_SERIALIZER_CTX_set_cipher(OSSL_SERIALIZER_CTX *ctx, + const char *cipher_name, + const char *propquery); + int OSSL_SERIALIZER_CTX_set_passphrase(OSSL_SERIALIZER_CTX *ctx, + const unsigned char *kstr, + size_t klen); + int OSSL_SERIALIZER_CTX_set_passphrase_cb(OSSL_SERIALIZER_CTX *ctx, int enc, + pem_password_cb *cb, void *cbarg); + int OSSL_SERIALIZER_CTX_set_passphrase_ui(OSSL_SERIALIZER_CTX *ctx, + const UI_METHOD *ui_method, + void *ui_data); + + #define OSSL_SERIALIZER_PUBKEY_TO_PEM_PQ "format=pem,type=public" + #define OSSL_SERIALIZER_PrivateKey_TO_PEM_PQ "format=pem,type=private" + #define OSSL_SERIALIZER_Parameters_TO_PEM_PQ "format=pem,type=domainparams" + + #define OSSL_SERIALIZER_PUBKEY_TO_TEXT_PQ "format=text,type=public" + #define OSSL_SERIALIZER_PrivateKey_TO_TEXT_PQ "format=text,type=private" + #define OSSL_SERIALIZER_Parameters_TO_TEXT_PQ "format=text,type=domainparams" + +=head1 DESCRIPTION + +OSSL_SERIALIZER_CTX_new_by_EVP_PKEY() creates a B<OSSL_SERIALIZER_CTX> +with a suitable attached output routine for B<EVP_PKEY>s. It will +search for a serializer implementation that matches the algorithm of +the B<EVP_PKEY> and the property query given with I<propquery>. It +will prefer to find a serializer from the same provider as the key +data of the B<EVP_PKEY> itself, but failing that, it will choose the +first serializer that supplies a generic serializing function. + +If no suitable serializer was found, OSSL_SERIALIZER_CTX_new_by_EVP_PKEY() +still creates a B<OSSL_SERIALIZER_CTX>, but with no associated +serializer (L<OSSL_SERIALIZER_CTX_get_serializer(3)> returns NULL). +This helps the caller distinguish between an error when creating +the B<OSSL_SERIALIZER_CTX>, and the lack the serializer support and +act accordingly. + +OSSL_SERIALIZER_CTX_set_cipher() tells the implementation what cipher +should be used to encrypt serialized keys. The cipher is given by +name I<cipher_name>. The interpretation of that I<cipher_name> is +implementation dependent. The implementation may implement the digest +directly itself or by other implementations, or it may choose to fetch +it. If the implementation supports fetching the cipher, then it may +use I<propquery> as properties to be queried for when fetching. +I<cipher_name> may also be NULL, which will result in unencrypted +serialization. + +OSSL_SERIALIZER_CTX_set_passphrase() gives the implementation a +pass phrase to use when encrypting the serialized private key. +Alternatively, a pass phrase callback may be specified with the +following functions. + +OSSL_SERIALIZER_CTX_set_passphrase_cb() and +OSSL_SERIALIZER_CTX_set_passphrase_ui() sets up a callback method that +the implementation can use to prompt for a pass phrase. + +=for comment Note that the callback method is called indirectly, +through an internal B<OSSL_PASSPHRASE_CALLBACK> function. + +The macros B<OSSL_SERIALIZER_PUBKEY_TO_PEM_PQ>, +B<OSSL_SERIALIZER_PrivateKey_TO_PEM_PQ>, +B<OSSL_SERIALIZER_Parameters_TO_PEM_PQ>, +B<OSSL_SERIALIZER_PUBKEY_TO_TEXT_PQ>, +B<OSSL_SERIALIZER_PrivateKey_TO_TEXT_PQ>, +B<OSSL_SERIALIZER_Parameters_TO_TEXT_PQ> are convenience macros with +property queries to serialize the B<EVP_PKEY> as a public key, private +key or parameters to B<PEM>, or to text. + +=head1 RETURN VALUES + +OSSL_SERIALIZER_CTX_new_by_EVP_PKEY() returns a pointer to a +B<OSSL_SERIALIZER_CTX>, or NULL if it couldn't be created. + +OSSL_SERIALIZER_CTX_set_cipher(), +OSSL_SERIALIZER_CTX_set_passphrase(), +OSSL_SERIALIZER_CTX_set_passphrase_cb(), and +OSSL_SERIALIZER_CTX_set_passphrase_ui() all return 1 on success, or 0 +on failure. + +=head1 NOTES + +Parts of the function and macro names are made to match already +existing OpenSSL names. + +B<EVP_PKEY> in OSSL_SERIALIZER_CTX_new_by_EVP_PKEY() matches the type +name, thus making for the naming pattern +B<OSSL_SERIALIZER_CTX_new_by_I<TYPE>>() when new types are handled. + +B<PUBKEY>, B<PrivateKey> and B<Parameters> in the macro names match +the B<I<TYPE>> part of of B<PEM_write_bio_I<TYPE>> functions as well +as B<i2d_I<TYPE>_bio> functions. + +=head1 SEE ALSO + +L<provider(7)>, L<OSSL_SERIALIZER(3)>, L<OSSL_SERIALIZER_CTX(3)> + +=head1 HISTORY + +The functions described here were added in OpenSSL 3.0. + +=head1 COPYRIGHT + +Copyright 2019 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 +in the file LICENSE in the source distribution or at +L<https://www.openssl.org/source/license.html>. + +=cut diff --git a/doc/man7/provider-serializer.pod b/doc/man7/provider-serializer.pod index e43e293d60..b23a8b64e2 100644 --- a/doc/man7/provider-serializer.pod +++ b/doc/man7/provider-serializer.pod @@ -193,6 +193,55 @@ Both serialization functions also take an B<OSSL_PASSPHRASE_CALLBACK> function pointer along with a pointer to application data I<cbarg>, which should be used when a pass phrase prompt is needed. +=head2 Serializer parameters + +Parameters currently recognised by built-in serializers are as +follows: + +=over 4 + +=item "cipher" (B<OSSL_SERIALIZER_PARAM_CIPHER>) <UTF8 string> + +The name of the encryption cipher to be used when generating encrypted +serialization. This is used when serializing private keys, as well as +other objects that need protection. + +If this name is invalid for the serialization implementation, the +implementation should refuse to perform the serialization, i.e. +OP_serializer_serialize_data() and OP_serializer_serialize_object() +should return an error. + +=item "properties" (B<OSSL_SERIALIZER_PARAM_PROPERTIES>) <UTF8 string> + +The properties to be queried when trying to fetch the algorithm given +with the "cipher" parameter. +This must be given together with the "cipher" parameter to be +considered valid. + +The serialization implementation isn't obligated to use this value. +However, it is recommended that implementations that do not handle +property strings return an error on receiving this parameter unless +its value NULL or the empty string. + +=item "passphrase" (B<OSSL_SERIALIZER_PARAM_PASS>) <octet string> + +A pass phrase provided by the application. When this is given, the +built-in serializers will not attempt to use the passphrase callback. + +=back + +Parameters currently recognised by the built-in pass phrase callback: + +=over 4 + +=item "info" (B<OSSL_PASSPHRASE_PARAM_INFO>) <UTF8 string> + +A string of information that will become part of the pass phrase +prompt. This could be used to give the user information on what kind +of object it's being prompted for. + +=back + =head1 RETURN VALUES OP_serializer_newctx() returns a pointer to a context, or NULL on diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h index 1e8b764fb4..053432e0f0 100644 --- a/include/openssl/core_names.h +++ b/include/openssl/core_names.h @@ -202,6 +202,17 @@ extern "C" { #define OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL "oaep-label" #define OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL_LEN "oaep-label-len" +/* + * Serializer parameters + */ +/* The passphrase may be passed as a utf8 string or an octet string */ +#define OSSL_SERIALIZER_PARAM_CIPHER OSSL_ALG_PARAM_CIPHER +#define OSSL_SERIALIZER_PARAM_PROPERTIES OSSL_ALG_PARAM_PROPERTIES +#define OSSL_SERIALIZER_PARAM_PASS "passphrase" + +/* Passphrase callback parameters */ +#define OSSL_PASSPHRASE_PARAM_INFO "info" + # ifdef __cplusplus } # endif diff --git a/include/openssl/err.h b/include/openssl/err.h index 37f3cc1d86..96b60882f0 100644 --- a/include/openssl/err.h +++ b/include/openssl/err.h @@ -233,6 +233,7 @@ struct err_state_st { # define ERR_R_PASSED_INVALID_ARGUMENT (7) # define ERR_R_OPERATION_FAIL (8|ERR_R_FATAL) # define ERR_R_INVALID_PROVIDER_FUNCTIONS (9|ERR_R_FATAL) +# define ERR_R_INTERRUPTED_OR_CANCELLED (10) /* * 99 is the maximum possible ERR_R_... code, higher values are reserved for diff --git a/include/openssl/serializer.h b/include/openssl/serializer.h index 78b57d225c..2629a13ccd 100644 --- a/include/openssl/serializer.h +++ b/include/openssl/serializer.h @@ -18,6 +18,7 @@ # endif # include <stdarg.h> # include <stddef.h> +# include <openssl/serializererr.h> # include <openssl/types.h> # include <openssl/core.h> @@ -53,12 +54,46 @@ int OSSL_SERIALIZER_CTX_set_params(OSSL_SERIALIZER_CTX *ctx, const OSSL_PARAM params[]); void OSSL_SERIALIZER_CTX_free(OSSL_SERIALIZER_CTX *ctx); +/* Utilities that help set specific parameters */ +int OSSL_SERIALIZER_CTX_set_cipher(OSSL_SERIALIZER_CTX *ctx, + const char *cipher_name, + const char *propquery); +int OSSL_SERIALIZER_CTX_set_passphrase(OSSL_SERIALIZER_CTX *ctx, + const unsigned char *kstr, + size_t klen); +int OSSL_SERIALIZER_CTX_set_passphrase_cb(OSSL_SERIALIZER_CTX *ctx, int enc, + pem_password_cb *cb, void *cbarg); +int OSSL_SERIALIZER_CTX_set_passphrase_ui(OSSL_SERIALIZER_CTX *ctx, + const UI_METHOD *ui_method, + void *ui_data); + /* Utilities to output the object to serialize */ int OSSL_SERIALIZER_to_bio(OSSL_SERIALIZER_CTX *ctx, BIO *out); #ifndef OPENSSL_NO_STDIO int OSSL_SERIALIZER_to_fp(OSSL_SERIALIZER_CTX *ctx, FILE *fp); #endif +/* + * Create the OSSL_SERIALIZER_CTX with an associated type. This will perform + * an implicit OSSL_SERIALIZER_fetch(), suitable for the object of that type. + * This is more useful than calling OSSL_SERIALIZER_CTX_new(). + */ +OSSL_SERIALIZER_CTX *OSSL_SERIALIZER_CTX_new_by_EVP_PKEY(const EVP_PKEY *pkey, + const char *propquery); + +/* + * These macros define the last argument to pass to + * OSSL_SERIALIZER_CTX_new_by_TYPE(). + */ +# define OSSL_SERIALIZER_PUBKEY_TO_PEM_PQ "format=pem,type=public" +# define OSSL_SERIALIZER_PrivateKey_TO_PEM_PQ "format=pem,type=private" +# define OSSL_SERIALIZER_Parameters_TO_PEM_PQ "format=pem,type=domainparams" + +/* Corresponding macros for text output */ +# define OSSL_SERIALIZER_PUBKEY_TO_TEXT_PQ "format=text,type=public" +# define OSSL_SERIALIZER_PrivateKey_TO_TEXT_PQ "format=text,type=private" +# define OSSL_SERIALIZER_Parameters_TO_TEXT_PQ "format=text,type=domainparams" + # ifdef __cplusplus } # endif diff --git a/include/openssl/serializererr.h b/include/openssl/serializererr.h new file mode 100644 index 0000000000..4eff9deab6 --- /dev/null +++ b/include/openssl/serializererr.h @@ -0,0 +1,34 @@ +/* + * Generated by util/mkerr.pl DO NOT EDIT + * Copyright 1995-2019 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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef OPENSSL_OSSL_SERIALIZERERR_H +# define OPENSSL_OSSL_SERIALIZERERR_H + +# include <openssl/opensslconf.h> +# include <openssl/symhacks.h> + + +# ifdef __cplusplus +extern "C" +# endif +int ERR_load_OSSL_SERIALIZER_strings(void); + +/* + * OSSL_SERIALIZER function codes. + */ +# ifndef OPENSSL_NO_DEPRECATED_3_0 +# endif |