213 lines
7.8 KiB
Plaintext
213 lines
7.8 KiB
Plaintext
|
=pod
|
||
|
|
||
|
=head1 NAME
|
||
|
|
||
|
EVP_PKEY - an internal description
|
||
|
|
||
|
=head1 SYNOPSIS
|
||
|
|
||
|
#include "crypto/evp.h"
|
||
|
|
||
|
typedef struct evp_pkey_st EVP_PKEY;
|
||
|
|
||
|
=head1 DESCRIPTION
|
||
|
|
||
|
I<This is not a complete description yet>
|
||
|
|
||
|
B<EVP_PKEY> 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<EVP_PKEY> contains is referred to
|
||
|
as its "internal key" or "origin" (the reason for "origin" is
|
||
|
explained further down, in L</Export cache for provider operations>),
|
||
|
and it can take one of the following forms:
|
||
|
|
||
|
=over 4
|
||
|
|
||
|
=item legacy origin
|
||
|
|
||
|
This is the form that an B<EVP_PKEY> in OpenSSL prior to 3.0 had. The
|
||
|
internal key in the B<EVP_PKEY> is a pointer to the low-level key
|
||
|
types, such as B<RSA>, B<DSA> and B<EC>, or an engine driven
|
||
|
structure, and is governed by an associated L<EVP_PKEY_METHOD(3)> and
|
||
|
an L<EVP_PKEY_ASN1_METHOD(3)>.
|
||
|
|
||
|
The functions available through those two method structures get full
|
||
|
access to the B<EVP_PKEY> and therefore have a lot of freedom to
|
||
|
modify whatever they want. This also means that an B<EVP_PKEY> 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<provider-keymgmt(7)>). The internal key in the
|
||
|
B<EVP_PKEY> is a pointer to that key data held by the provider, and
|
||
|
is governed by an associated L<EVP_KEYMGMT(3)> method structure.
|
||
|
|
||
|
The functions available through the L<EVP_KEYMGMT(3)> have no access
|
||
|
to the B<EVP_PKEY>, and can therefore not make any direct changes.
|
||
|
Similarly, the key data that the B<EVP_PKEY> points at is only known
|
||
|
to the functions pointed at in the L<EVP_KEYMGMT(3)>.
|
||
|
|
||
|
=back
|
||
|
|
||
|
These two forms can never co-exist in the same B<EVP_PKEY>, 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<EVP_PKEY> internal keys are mutable.
|
||
|
|
||
|
This is especially visible with internal legacy keys, since they can
|
||
|
be extracted with functions like L<EVP_PKEY_get0_RSA(3)> and then
|
||
|
modified at will with functions like L<RSA_set0_key(3)>. Note that if the
|
||
|
internal key is a provider key then the return value from functions such as
|
||
|
L<EVP_PKEY_get0_RSA(3)> 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<EVP_KEYMGMT(3)> implementation allows it. This is done
|
||
|
with L<EVP_PKEY_set_params(3)> 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<EVP_PKEY_set1_encoded_public_key(3)>.
|
||
|
|
||
|
=item EC:
|
||
|
|
||
|
It's possible to flip the ECDH cofactor mode.
|
||
|
|
||
|
=back
|
||
|
|
||
|
Every time the B<EVP_PKEY> internal key mutates, an internal dirty
|
||
|
count is incremented. The need for a dirty count is explained further
|
||
|
in L</Export cache for provider operations>.
|
||
|
|
||
|
For provider native origin keys, this doesn't require any help from
|
||
|
the L<EVP_KEYMGMT(3)>, the dirty count is maintained in the B<EVP_PKEY>
|
||
|
itself, and is incremented every time L<EVP_PKEY_set_params(3)> or its
|
||
|
specialised derivatives are called.
|
||
|
For legacy origin keys, this requires the associated
|
||
|
L<EVP_PKEY_ASN1_METHOD(3)> to implement the dirty_cnt() function. All
|
||
|
of OpenSSL's built-in L<EVP_PKEY_ASN1_METHOD(3)> 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<EVP_KEYMGMT(3)>. 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<EVP_KEYMGMT(3)>).
|
||
|
|
||
|
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<EVP_PKEY>. Each cache entry has two items, a pointer to the
|
||
|
provider side key data and the associated L<EVP_KEYMGMT(3)>.
|
||
|
|
||
|
I<This cache is often referred to as the "operation key cache", and
|
||
|
the key data that the cached keys came from is the "origin", and since
|
||
|
there are two forms of the latter, we have the "legacy origin" and the
|
||
|
"provider native origin".>
|
||
|
|
||
|
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<EVP_PKEY_ASN1_METHOD(3)> implements the functions export_to() and
|
||
|
dirty_cnt().
|
||
|
For a provider native origin, this requires that the associated
|
||
|
L<EVP_KEYMGMT(3)> implements the OSSL_FUNC_keymgmt_export() function
|
||
|
(see L<provider-keymgmt(7)>).
|
||
|
In all cases, the receiving L<EVP_KEYMGMT(3)> (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<EVP_KEYMGMT(3)> 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<EVP_PKEY> is going to be used).
|
||
|
|
||
|
If such an entry is found, nothing more is done, the key data and
|
||
|
L<EVP_KEYMGMT(3)> 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<EVP_PKEY_ASN1_METHOD(3)> export_to() function.
|
||
|
|
||
|
For provider native origin keys, that's done by retrieving the key
|
||
|
data in L<OSSL_PARAM(3)> form from the origin keys, using the
|
||
|
OSSL_FUNC_keymgmt_export() functions of the associated
|
||
|
L<EVP_KEYMGMT(3)>, and sending that data to the L<EVP_KEYMGMT(3)> 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<EVP_PKEY> with a legacy
|
||
|
origin will I<never> be upgraded to become an B<EVP_PKEY> 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<EVP_PKEY> with a provider native origin, will I<never> be
|
||
|
I<transformed> into an B<EVP_PKEY> 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<provider-keymgmt(7)>
|
||
|
|
||
|
=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<https://www.openssl.org/source/license.html>.
|
||
|
|
||
|
=cut
|