=pod =head1 NAME EVP_PKEY - an internal description =head1 SYNOPSIS #include "crypto/evp.h" typedef struct evp_pkey_st EVP_PKEY; =head1 DESCRIPTION I B is a complex type that's essentially a container for private/public key pairs, but has had other uses as well. =for comment "uses" could as well be "abuses"... The private/public key pair that an B contains is referred to as its "internal key" or "origin" (the reason for "origin" is explained further down, in L), and it can take one of the following forms: =over 4 =item legacy origin This is the form that an B in OpenSSL prior to 3.0 had. The internal key in the B is a pointer to the low-level key types, such as B, B and B, or an engine driven structure, and is governed by an associated L and an L. The functions available through those two method structures get full access to the B and therefore have a lot of freedom to modify whatever they want. This also means that an B is a shared structure between libcrypto and any ENGINE that serves such methods. =item provider-native origin This is a new form in OpenSSL 3.0, which permits providers to hold the key data (see L). The internal key in the B is a pointer to that key data held by the provider, and is governed by an associated L method structure. The functions available through the L have no access to the B, and can therefore not make any direct changes. Similarly, the key data that the B points at is only known to the functions pointed at in the L. =back These two forms can never co-exist in the same B, the main reason being that having both at the same time will create problems with synchronising between the two forms, and potentially make it confusing which one of the two is the origin. =head2 Key mutability The B internal keys are mutable. This is especially visible with internal legacy keys, since they can be extracted with functions like L and then modified at will with functions like L. Note that if the internal key is a provider key then the return value from functions such as L is a cached copy of the key. Changes to the cached copy are not reflected back in the provider key. Internal provider native keys are also possible to be modified, if the associated L implementation allows it. This is done with L and its specialised derivatives. The OpenSSL providers allow it for the following: =over 4 =item DH, EC, X25519, X448: It's possible to set the encoded public key. This is supported in particular through L. =item EC: It's possible to flip the ECDH cofactor mode. =back Every time the B internal key mutates, an internal dirty count is incremented. The need for a dirty count is explained further in L. For provider native origin keys, this doesn't require any help from the L, the dirty count is maintained in the B itself, and is incremented every time L or its specialised derivatives are called. For legacy origin keys, this requires the associated L to implement the dirty_cnt() function. All of OpenSSL's built-in L implement this function. =head2 Export cache for provider operations OpenSSL 3.0 can handle operations such as signing, encrypting, etc in diverse providers, potentially others than the provider of the L. Two providers, possibly from different vendors, can't be expected to share internal key structures. There are therefore instances where key data will need to be exported to the provider that is going to perform the operation (this also implies that every provider that implements a key pair based operation must also implement an L). For performance reasons, libcrypto tries to minimize the need to perform such an export, so it maintains a cache of such exports in the B. Each cache entry has two items, a pointer to the provider side key data and the associated L. I The export to the operation key cache can be performed independent of what form the origin has. For a legacy origin, this requires that the associated L implements the functions export_to() and dirty_cnt(). For a provider native origin, this requires that the associated L implements the OSSL_FUNC_keymgmt_export() function (see L). In all cases, the receiving L (the one associated with the exported key data) must implement OSSL_FUNC_keymgmt_import(). If such caching isn't supported, the operations that can be performed with that key are limited to the same backend as the origin key (ENGINE for legacy origin keys, provider for provider side origin keys). =head3 Exporting implementation details Exporting a key to the operation cache involves the following: =over 4 =item 1. Check if the dirty count for the internal origin key has changed since the previous time. This is done by comparing it with a copy of the dirty count, which is maintained by the export function. If the dirty count has changed, the export cache is cleared. =item 2. Check if there's an entry in the export cache with the same L that's the same provider that an export is to be made to (which is the provider that's going to perform an operation for which the current B is going to be used). If such an entry is found, nothing more is done, the key data and L found in that export cache entry will be used for the operation to be performed. =item 3. Export the internal origin key to the provider, using the appropriate method. For legacy origin keys, that's done with the help of the L export_to() function. For provider native origin keys, that's done by retrieving the key data in L form from the origin keys, using the OSSL_FUNC_keymgmt_export() functions of the associated L, and sending that data to the L of the provider that's to perform the operation, using its OSSL_FUNC_keymgmt_import() function. =back =head2 Changing a key origin It is never possible to change the origin of a key. An B with a legacy origin will I be upgraded to become an B with a provider native origin. Instead, we have the operation cache as described above, that takes care of the needs of the diverse operation the application may want to perform. Similarly an B with a provider native origin, will I be I into an B with a legacy origin. Instead we may have a cached copy of the provider key in legacy form. Once the cached copy is created it is never updated. Changes made to the provider key are not reflected back in the cached legacy copy. Similarly changes made to the cached legacy copy are not reflected back in the provider key. =head1 SEE ALSO L =head1 COPYRIGHT Copyright 2020-2022 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. =cut