mirror of https://github.com/openssl/openssl.git
				
				
				
			
		
			
	
	
		
			206 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			Markdown
		
	
	
	
		
		
			
		
	
	
			206 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			Markdown
		
	
	
	
| 
								 | 
							
								Functions for explicitly fetched PKEY algorithms
							 | 
						||
| 
								 | 
							
								================================================
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Quick background
							 | 
						||
| 
								 | 
							
								----------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								There are several proposed designs that end up revolving around the same
							 | 
						||
| 
								 | 
							
								basic need, explicitly fetched signature algorithms.  The following method
							 | 
						||
| 
								 | 
							
								type is affected by this document:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								- `EVP_SIGNATURE`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Public API - Add variants of `EVP_PKEY_CTX` functionality
							 | 
						||
| 
								 | 
							
								---------------------------------------------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Through OTC discussions, it's been determined that the most suitable APIs to
							 | 
						||
| 
								 | 
							
								touch are the of `EVP_PKEY_` functions.
							 | 
						||
| 
								 | 
							
								Specifically, `EVP_PKEY_sign()`, `EVP_PKEY_verify()`, `EVP_PKEY_verify_recover()`
							 | 
						||
| 
								 | 
							
								and related functions.
							 | 
						||
| 
								 | 
							
								They can be extended to accept an explicitly fetched algorithm of the right
							 | 
						||
| 
								 | 
							
								type, and to be able to incrementally process indefinite length data streams
							 | 
						||
| 
								 | 
							
								when the fetched algorithm permits it (for example, RSA-SHA256).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								It must be made clear that the added functionality cannot be used to compose
							 | 
						||
| 
								 | 
							
								an algorithm from different parts.  For example, it's not possible to specify
							 | 
						||
| 
								 | 
							
								a `EVP_SIGNATURE` "RSA" and combine it with a parameter that specifies the
							 | 
						||
| 
								 | 
							
								hash "SHA256" to get the "RSA-SHA256" functionality.  For an `EVP_SIGNATURE`
							 | 
						||
| 
								 | 
							
								"RSA", the input is still expected to be a digest, or some other input that's
							 | 
						||
| 
								 | 
							
								limited to the modulus size of the RSA pkey.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Making things less confusing with distinct function names
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Until now, `EVP_PKEY_sign()` and friends were only expected to act on the
							 | 
						||
| 
								 | 
							
								pre-computed digest of a message (under the condition that proper flags
							 | 
						||
| 
								 | 
							
								and signature md are specified using functions like
							 | 
						||
| 
								 | 
							
								`EVP_PKEY_CTX_set_rsa_padding()` and `EVP_PKEY_CTX_set_signature_md()`),
							 | 
						||
| 
								 | 
							
								or to act as "primitive" [^1] functions (under the condition that proper
							 | 
						||
| 
								 | 
							
								flags are specified, like `RSA_NO_PADDING` for RSA signatures).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This design proposes an extension to also allow full (not pre-hashed)
							 | 
						||
| 
								 | 
							
								messages to be passed, in a streaming style through an *update* and a
							 | 
						||
| 
								 | 
							
								*final* function.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Discussions have revealed that it is potentially confusing to conflate the
							 | 
						||
| 
								 | 
							
								current functionality with streaming style functionality into the same name,
							 | 
						||
| 
								 | 
							
								so this design separates those out with specific init / update / final
							 | 
						||
| 
								 | 
							
								functions for that purpose.  For oneshot functionality, `EVP_PKEY_sign()`
							 | 
						||
| 
								 | 
							
								and `EVP_PKEY_verify()` remain supported.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[^1]: the term "primitive" is borrowed from [PKCS#1](https://www.rfc-editor.org/rfc/rfc8017#section-5)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Making it possible to verify with an early signature
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Some more recent verification algorithms need to obtain the signature
							 | 
						||
| 
								 | 
							
								before processing the data.
							 | 
						||
| 
								 | 
							
								This is particularly important for streaming modes of operation.
							 | 
						||
| 
								 | 
							
								This design proposes a mechanism to accomodate these algorithms
							 | 
						||
| 
								 | 
							
								and modes of operation.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								New public API - API Reference
							 | 
						||
| 
								 | 
							
								------------------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### For limited input size / oneshot signing with `EVP_SIGNATURE`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								``` C
							 | 
						||
| 
								 | 
							
								int EVP_PKEY_sign_init_ex2(EVP_PKEY_CTX *pctx,
							 | 
						||
| 
								 | 
							
								                           EVP_SIGNATURE *algo,
							 | 
						||
| 
								 | 
							
								                           const OSSL_PARAM params[]);
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### For signing a stream with `EVP_SIGNATURE`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								``` C
							 | 
						||
| 
								 | 
							
								int EVP_PKEY_sign_message_init(EVP_PKEY_CTX *pctx,
							 | 
						||
| 
								 | 
							
								                               EVP_SIGNATURE *algo,
							 | 
						||
| 
								 | 
							
								                               const OSSL_PARAM params[]);
							 | 
						||
| 
								 | 
							
								int EVP_PKEY_sign_message_update(EVP_PKEY_CTX *ctx,
							 | 
						||
| 
								 | 
							
								                                 const unsigned char *in,
							 | 
						||
| 
								 | 
							
								                                 size_t inlen);
							 | 
						||
| 
								 | 
							
								int EVP_PKEY_sign_message_final(EVP_PKEY_CTX *ctx,
							 | 
						||
| 
								 | 
							
								                                unsigned char *sig,
							 | 
						||
| 
								 | 
							
								                                size_t *siglen);
							 | 
						||
| 
								 | 
							
								#define EVP_PKEY_sign_message(ctx,sig,siglen,tbs,tbslen) \
							 | 
						||
| 
								 | 
							
								    EVP_PKEY_sign(ctx,sig,siglen,tbs,tbslen)
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### For limited input size / oneshot verification with `EVP_SIGNATURE`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								``` C
							 | 
						||
| 
								 | 
							
								int EVP_PKEY_verify_init_ex2(EVP_PKEY_CTX *pctx,
							 | 
						||
| 
								 | 
							
								                             EVP_SIGNATURE *algo,
							 | 
						||
| 
								 | 
							
								                             const OSSL_PARAM params[]);
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### For verifying a stream with `EVP_SIGNATURE`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								``` C
							 | 
						||
| 
								 | 
							
								/* Initializers */
							 | 
						||
| 
								 | 
							
								int EVP_PKEY_verify_message_init(EVP_PKEY_CTX *pctx,
							 | 
						||
| 
								 | 
							
								                                 EVP_SIGNATURE *algo,
							 | 
						||
| 
								 | 
							
								                                 const OSSL_PARAM params[]);
							 | 
						||
| 
								 | 
							
								/* Signature setter */
							 | 
						||
| 
								 | 
							
								int EVP_PKEY_CTX_set_signature(EVP_PKEY_CTX *pctx,
							 | 
						||
| 
								 | 
							
								                               unsigned char *sig, size_t siglen,
							 | 
						||
| 
								 | 
							
								                               size_t sigsize);
							 | 
						||
| 
								 | 
							
								/* Update and final */
							 | 
						||
| 
								 | 
							
								int EVP_PKEY_verify_message_update(EVP_PKEY_CTX *ctx,
							 | 
						||
| 
								 | 
							
								                                   const unsigned char *in,
							 | 
						||
| 
								 | 
							
								                                   size_t inlen);
							 | 
						||
| 
								 | 
							
								int EVP_PKEY_verify_message_final(EVP_PKEY_CTX *ctx);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define EVP_PKEY_verify_message(ctx,sig,siglen,tbs,tbslen) \
							 | 
						||
| 
								 | 
							
								    EVP_PKEY_verify(ctx,sig,siglen,tbs,tbslen)
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### For verify_recover with `EVP_SIGNATURE`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Preliminary feedback suggests that a streaming interface is uninteresting for
							 | 
						||
| 
								 | 
							
								verify_recover, so we only specify a new init function.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								``` C
							 | 
						||
| 
								 | 
							
								/* Initializers */
							 | 
						||
| 
								 | 
							
								int EVP_PKEY_verify_recover_init_ex2(EVP_PKEY_CTX *pctx,
							 | 
						||
| 
								 | 
							
								                                     EVP_SIGNATURE *algo,
							 | 
						||
| 
								 | 
							
								                                     const OSSL_PARAM params[]);
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Requirements on the providers
							 | 
						||
| 
								 | 
							
								-----------------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Because it's not immediately obvious from a composite algorithm name what
							 | 
						||
| 
								 | 
							
								key type ("RSA", "EC", ...) it requires / supports, at least in code, allowing
							 | 
						||
| 
								 | 
							
								the use of an explicitly fetched implementation of a composite algorithm
							 | 
						||
| 
								 | 
							
								requires that providers cooperate by declaring what key type is required /
							 | 
						||
| 
								 | 
							
								supported by each algorithm.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								For non-composite operation algorithms (like "RSA"), this is not necessary,
							 | 
						||
| 
								 | 
							
								see the fallback strategies below.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This is to be implemented through an added provider function that would work
							 | 
						||
| 
								 | 
							
								like keymgmt's `query_operation_name` function, but would return a NULL
							 | 
						||
| 
								 | 
							
								terminated array of key type name instead:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								``` C
							 | 
						||
| 
								 | 
							
								# define OSSL_FUNC_SIGNATURE_QUERY_KEY_TYPE         26
							 | 
						||
| 
								 | 
							
								OSSL_CORE_MAKE_FUNC(const char **, signature_query_key_type, (void))
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Furthermore, the distinction of intent, i.e. whether the input is expected
							 | 
						||
| 
								 | 
							
								to be a pre-hashed digest or the original message, must be passed on to the
							 | 
						||
| 
								 | 
							
								provider.  Because we already distinguish that with function names in the
							 | 
						||
| 
								 | 
							
								public API, we use the same mapping in the provider interface.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The already existing `signature_sign` and `signature_verify` remain as they
							 | 
						||
| 
								 | 
							
								are, and can be combined with message init calls.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								``` C
							 | 
						||
| 
								 | 
							
								# define OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_INIT      27
							 | 
						||
| 
								 | 
							
								# define OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_UPDATE    28
							 | 
						||
| 
								 | 
							
								# define OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_FINAL     29
							 | 
						||
| 
								 | 
							
								OSSL_CORE_MAKE_FUNC(int, signature_sign_message_init,
							 | 
						||
| 
								 | 
							
								                    (void *ctx, void *provkey, const OSSL_PARAM params[]))
							 | 
						||
| 
								 | 
							
								OSSL_CORE_MAKE_FUNC(int, signature_sign_message_update,
							 | 
						||
| 
								 | 
							
								                    (void *ctx, const unsigned char *in, size_t inlen))
							 | 
						||
| 
								 | 
							
								OSSL_CORE_MAKE_FUNC(int, signature_sign_message_final,
							 | 
						||
| 
								 | 
							
								                    (void *ctx, unsigned char *sig, size_t *siglen, size_t sigsize))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# define OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_INIT    30
							 | 
						||
| 
								 | 
							
								# define OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_UPDATE  31
							 | 
						||
| 
								 | 
							
								# define OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_FINAL   32
							 | 
						||
| 
								 | 
							
								OSSL_CORE_MAKE_FUNC(int, signature_verify_message_init,
							 | 
						||
| 
								 | 
							
								                    (void *ctx, void *provkey, const OSSL_PARAM params[]))
							 | 
						||
| 
								 | 
							
								OSSL_CORE_MAKE_FUNC(int, signature_verify_message_update,
							 | 
						||
| 
								 | 
							
								                    (void *ctx, const unsigned char *in, size_t inlen))
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * signature_verify_message_final requires that the signature to be verified
							 | 
						||
| 
								 | 
							
								 * against is specified via an OSSL_PARAM.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								OSSL_CORE_MAKE_FUNC(int, signature_verify_message_final, (void *ctx))
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Fallback strategies
							 | 
						||
| 
								 | 
							
								-------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Because existing providers haven't been updated to respond to the key type
							 | 
						||
| 
								 | 
							
								query, some fallback strategies will be needed for the init calls that take
							 | 
						||
| 
								 | 
							
								an explicitly fetched `EVP_SIGNATURE` argument (they can at least be used
							 | 
						||
| 
								 | 
							
								for pre-hashed digest operations).  To find out if the `EVP_PKEY` key type
							 | 
						||
| 
								 | 
							
								is possible to use with the explicitly fetched algorithm, the following
							 | 
						||
| 
								 | 
							
								fallback strategies may be used.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								-   Check if the fetched operation name matches the key type (keymgmt name)
							 | 
						||
| 
								 | 
							
								    of the `EVP_PKEY` that's involved in the operation.  For example, this
							 | 
						||
| 
								 | 
							
								    is useful when someone fetched the `EVP_SIGNATURE` "RSA".  This requires
							 | 
						||
| 
								 | 
							
								    very little modification, as this is already done with the initializer
							 | 
						||
| 
								 | 
							
								    functions that fetch the algorithm implicitly.
							 | 
						||
| 
								 | 
							
								-   Check if the fetched algorithm name matches the name returned by the
							 | 
						||
| 
								 | 
							
								    keymgmt's `query_operation_name` function.  For example, this is useful
							 | 
						||
| 
								 | 
							
								    when someone fetched the `EVP_SIGNATURE` "ECDSA", for which the key type
							 | 
						||
| 
								 | 
							
								    to use is "EC".  This requires very little modification, as this is
							 | 
						||
| 
								 | 
							
								    already done with the initializer functions that fetch the algorithm
							 | 
						||
| 
								 | 
							
								    implicitly.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								If none of these strategies work out, the operation initialization should
							 | 
						||
| 
								 | 
							
								fail.
							 |