| 
									
										
										
										
											2020-02-24 21:36:09 +08:00
										 |  |  | =pod | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =head1 NAME | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | EVP_PKEY - an internal description | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =head1 SYNOPSIS | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  #include "crypto/evp.h" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-04 03:40:37 +08:00
										 |  |  |  typedef struct evp_pkey_st EVP_PKEY; | 
					
						
							| 
									
										
										
										
											2020-02-24 21:36:09 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | =head1 DESCRIPTION | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | I<This is not a complete description yet> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | B<EVP_PKEY> is a complex type that's essentially a container for | 
					
						
							| 
									
										
										
										
											2021-02-04 03:40:37 +08:00
										 |  |  | private/public key pairs, but has had other uses as well. | 
					
						
							| 
									
										
										
										
											2020-02-24 21:36:09 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | =for comment "uses" could as well be "abuses"... | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-04 03:40:37 +08:00
										 |  |  | 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(). | 
					
						
							| 
									
										
										
										
											2020-02-24 21:36:09 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | If such caching isn't supported, the operations that can be performed | 
					
						
							| 
									
										
										
										
											2021-02-04 03:40:37 +08:00
										 |  |  | with that key are limited to the same backend as the origin key | 
					
						
							|  |  |  | (ENGINE for legacy origin keys, provider for provider side origin | 
					
						
							| 
									
										
										
										
											2020-02-24 21:36:09 +08:00
										 |  |  | keys). | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-04 03:40:37 +08:00
										 |  |  | =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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-25 00:38:28 +08:00
										 |  |  | =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. | 
					
						
							| 
									
										
										
										
											2021-02-04 03:40:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-24 21:36:09 +08:00
										 |  |  | =head1 SEE ALSO | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | L<provider-keymgmt(7)> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =head1 COPYRIGHT | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-18 22:57:13 +08:00
										 |  |  | Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. | 
					
						
							| 
									
										
										
										
											2020-02-24 21:36:09 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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 |