mirror of https://github.com/openssl/openssl.git
				
				
				
			
		
			
				
	
	
		
			210 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
			
		
		
	
	
			210 lines
		
	
	
		
			7.6 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 refered 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)>.
 | |
| 
 | |
| 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
 | |
| downgraded to 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-2021 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
 |