mirror of https://github.com/openssl/openssl.git
				
				
				
			Add X25519/X448 Key Exchange to the default provider
Reviewed-by: Patrick Steuer <patrick.steuer@de.ibm.com> Reviewed-by: Shane Lontis <shane.lontis@oracle.com> (Merged from https://github.com/openssl/openssl/pull/10964)
This commit is contained in:
		
							parent
							
								
									90d3cb57c6
								
							
						
					
					
						commit
						6f7d213533
					
				|  | @ -18,6 +18,8 @@ | |||
| #include <openssl/x509.h> | ||||
| #include <openssl/ec.h> | ||||
| #include <openssl/rand.h> | ||||
| #include <openssl/core_names.h> | ||||
| #include "internal/param_build.h" | ||||
| #include "crypto/asn1.h" | ||||
| #include "crypto/evp.h" | ||||
| #include "crypto/ecx.h" | ||||
|  | @ -401,6 +403,48 @@ static int ecx_get_pub_key(const EVP_PKEY *pkey, unsigned char *pub, | |||
|     return 1; | ||||
| } | ||||
| 
 | ||||
| static size_t ecx_pkey_dirty_cnt(const EVP_PKEY *pkey) | ||||
| { | ||||
|     /*
 | ||||
|      * We provide no mechanism to "update" an ECX key once it has been set, | ||||
|      * therefore we do not have to maintain a dirty count. | ||||
|      */ | ||||
|     return 1; | ||||
| } | ||||
| 
 | ||||
| static int ecx_pkey_export_to(const EVP_PKEY *from, void *to_keydata, | ||||
|                               EVP_KEYMGMT *to_keymgmt) | ||||
| { | ||||
|     const ECX_KEY *key = from->pkey.ecx; | ||||
|     OSSL_PARAM_BLD tmpl; | ||||
|     OSSL_PARAM *params = NULL; | ||||
|     int rv = 0; | ||||
| 
 | ||||
|     ossl_param_bld_init(&tmpl); | ||||
| 
 | ||||
|     /* A key must at least have a public part */ | ||||
|     if (!ossl_param_bld_push_octet_string(&tmpl, OSSL_PKEY_PARAM_PUB_KEY, | ||||
|                                           key->pubkey, key->keylen)) | ||||
|         goto err; | ||||
| 
 | ||||
|     if (key->privkey != NULL) { | ||||
|         if (!ossl_param_bld_push_octet_string(&tmpl, | ||||
|                                               OSSL_PKEY_PARAM_PRIV_KEY, | ||||
|                                               key->privkey, key->keylen)) | ||||
|             goto err; | ||||
|     } | ||||
| 
 | ||||
|     params = ossl_param_bld_to_param(&tmpl); | ||||
| 
 | ||||
|     /* We export, the provider imports */ | ||||
|     rv = evp_keymgmt_import(to_keymgmt, to_keydata, OSSL_KEYMGMT_SELECT_ALL, | ||||
|                             params); | ||||
| 
 | ||||
|  err: | ||||
|     ossl_param_bld_free(params); | ||||
|     return rv; | ||||
| } | ||||
| 
 | ||||
| const EVP_PKEY_ASN1_METHOD ecx25519_asn1_meth = { | ||||
|     EVP_PKEY_X25519, | ||||
|     EVP_PKEY_X25519, | ||||
|  | @ -442,6 +486,8 @@ const EVP_PKEY_ASN1_METHOD ecx25519_asn1_meth = { | |||
|     ecx_set_pub_key, | ||||
|     ecx_get_priv_key, | ||||
|     ecx_get_pub_key, | ||||
|     ecx_pkey_dirty_cnt, | ||||
|     ecx_pkey_export_to | ||||
| }; | ||||
| 
 | ||||
| const EVP_PKEY_ASN1_METHOD ecx448_asn1_meth = { | ||||
|  | @ -485,6 +531,8 @@ const EVP_PKEY_ASN1_METHOD ecx448_asn1_meth = { | |||
|     ecx_set_pub_key, | ||||
|     ecx_get_priv_key, | ||||
|     ecx_get_pub_key, | ||||
|     ecx_pkey_dirty_cnt, | ||||
|     ecx_pkey_export_to | ||||
| }; | ||||
| 
 | ||||
| static int ecd_size25519(const EVP_PKEY *pkey) | ||||
|  |  | |||
|  | @ -1822,13 +1822,13 @@ X509V3_F_X509_PURPOSE_SET:141:X509_PURPOSE_set | |||
| X509_F_ADD_CERT_DIR:100:add_cert_dir | ||||
| X509_F_BUILD_CHAIN:106:build_chain | ||||
| X509_F_BY_FILE_CTRL:101:by_file_ctrl | ||||
| X509_F_CACHE_OBJECTS:163:cache_objects | ||||
| X509_F_CHECK_NAME_CONSTRAINTS:149:check_name_constraints | ||||
| X509_F_CHECK_POLICY:145:check_policy | ||||
| X509_F_COMMON_VERIFY_SM2:165:common_verify_sm2 | ||||
| X509_F_DANE_I2D:107:dane_i2d | ||||
| X509_F_DIR_CTRL:102:dir_ctrl | ||||
| X509_F_GET_CERT_BY_SUBJECT:103:get_cert_by_subject | ||||
| X509_F_CACHE_OBJECTS:163:cache_objects | ||||
| X509_F_I2D_X509_AUX:151:i2d_X509_AUX | ||||
| X509_F_LOOKUP_CERTS_SK:152:lookup_certs_sk | ||||
| X509_F_NETSCAPE_SPKI_B64_DECODE:129:NETSCAPE_SPKI_b64_decode | ||||
|  | @ -2741,6 +2741,7 @@ PROV_R_BAD_TLS_CLIENT_VERSION:161:bad tls client version | |||
| PROV_R_BN_ERROR:160:bn error | ||||
| PROV_R_BOTH_MODE_AND_MODE_INT:127:both mode and mode int | ||||
| PROV_R_CIPHER_OPERATION_FAILED:102:cipher operation failed | ||||
| PROV_R_FAILED_DURING_DERIVATION:164:failed during derivation | ||||
| PROV_R_FAILED_TO_DECRYPT:162:failed to decrypt | ||||
| PROV_R_FAILED_TO_GENERATE_KEY:121:failed to generate key | ||||
| PROV_R_FAILED_TO_GET_PARAMETER:103:failed to get parameter | ||||
|  |  | |||
|  | @ -57,6 +57,7 @@ int ERR_load_PROV_strings(void); | |||
| # define PROV_R_BN_ERROR                                  160 | ||||
| # define PROV_R_BOTH_MODE_AND_MODE_INT                    127 | ||||
| # define PROV_R_CIPHER_OPERATION_FAILED                   102 | ||||
| # define PROV_R_FAILED_DURING_DERIVATION                  164 | ||||
| # define PROV_R_FAILED_TO_DECRYPT                         162 | ||||
| # define PROV_R_FAILED_TO_GENERATE_KEY                    121 | ||||
| # define PROV_R_FAILED_TO_GET_PARAMETER                   103 | ||||
|  |  | |||
|  | @ -26,6 +26,8 @@ static const ERR_STRING_DATA PROV_str_reasons[] = { | |||
|     "both mode and mode int"}, | ||||
|     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_CIPHER_OPERATION_FAILED), | ||||
|     "cipher operation failed"}, | ||||
|     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_FAILED_DURING_DERIVATION), | ||||
|     "failed during derivation"}, | ||||
|     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_FAILED_TO_DECRYPT), "failed to decrypt"}, | ||||
|     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_FAILED_TO_GENERATE_KEY), | ||||
|     "failed to generate key"}, | ||||
|  |  | |||
|  | @ -371,6 +371,10 @@ static const OSSL_ALGORITHM deflt_kdfs[] = { | |||
| static const OSSL_ALGORITHM deflt_keyexch[] = { | ||||
| #ifndef OPENSSL_NO_DH | ||||
|     { "DH:dhKeyAgreement", "default=yes", dh_keyexch_functions }, | ||||
| #endif | ||||
| #ifndef OPENSSL_NO_EC | ||||
|     { "X25519", "default=yes", x25519_keyexch_functions }, | ||||
|     { "X448", "default=yes", x448_keyexch_functions }, | ||||
| #endif | ||||
|     { NULL, NULL, NULL } | ||||
| }; | ||||
|  |  | |||
|  | @ -2,7 +2,10 @@ | |||
| # switch each to the Legacy provider when needed. | ||||
| 
 | ||||
| $DH_GOAL=../../libimplementations.a | ||||
| $ECX_GOAL=../../libimplementations.a | ||||
| 
 | ||||
| IF[{- !$disabled{dh} -}] | ||||
|   SOURCE[$DH_GOAL]=dh_exch.c | ||||
| ENDIF | ||||
| 
 | ||||
| SOURCE[$ECX_GOAL]=ecx_exch.c | ||||
|  |  | |||
|  | @ -0,0 +1,200 @@ | |||
| /*
 | ||||
|  * Copyright 2020 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 | ||||
|  * https://www.openssl.org/source/license.html
 | ||||
|  */ | ||||
| 
 | ||||
| #include <openssl/crypto.h> | ||||
| #include <openssl/core_numbers.h> | ||||
| #include <openssl/core_names.h> | ||||
| #include <openssl/params.h> | ||||
| #include <openssl/err.h> | ||||
| #include "internal/cryptlib.h" | ||||
| #include "crypto/ecx.h" | ||||
| #include "prov/implementations.h" | ||||
| #include "prov/providercommonerr.h" | ||||
| 
 | ||||
| static OSSL_OP_keyexch_newctx_fn x25519_newctx; | ||||
| static OSSL_OP_keyexch_newctx_fn x448_newctx; | ||||
| static OSSL_OP_keyexch_init_fn ecx_init; | ||||
| static OSSL_OP_keyexch_set_peer_fn ecx_set_peer; | ||||
| static OSSL_OP_keyexch_derive_fn ecx_derive; | ||||
| static OSSL_OP_keyexch_freectx_fn ecx_freectx; | ||||
| static OSSL_OP_keyexch_dupctx_fn ecx_dupctx; | ||||
| 
 | ||||
| /*
 | ||||
|  * What's passed as an actual key is defined by the KEYMGMT interface. | ||||
|  * We happen to know that our KEYMGMT simply passes ECX_KEY structures, so | ||||
|  * we use that here too. | ||||
|  */ | ||||
| 
 | ||||
| typedef struct { | ||||
|     size_t keylen; | ||||
|     ECX_KEY *key; | ||||
|     ECX_KEY *peerkey; | ||||
| } PROV_ECX_CTX; | ||||
| 
 | ||||
| static void *ecx_newctx(void *provctx, size_t keylen) | ||||
| { | ||||
|     PROV_ECX_CTX *ctx = OPENSSL_zalloc(sizeof(PROV_ECX_CTX)); | ||||
| 
 | ||||
|     if (ctx == NULL) { | ||||
|         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     ctx->keylen = keylen; | ||||
| 
 | ||||
|     return ctx; | ||||
| } | ||||
| 
 | ||||
| static void *x25519_newctx(void *provctx) | ||||
| { | ||||
|     return ecx_newctx(provctx, X25519_KEYLEN); | ||||
| } | ||||
| 
 | ||||
| static void *x448_newctx(void *provctx) | ||||
| { | ||||
|     return ecx_newctx(provctx, X448_KEYLEN); | ||||
| } | ||||
| 
 | ||||
| static int ecx_init(void *vecxctx, void *vkey) | ||||
| { | ||||
|     PROV_ECX_CTX *ecxctx = (PROV_ECX_CTX *)vecxctx; | ||||
|     ECX_KEY *key = vkey; | ||||
| 
 | ||||
|     if (ecxctx == NULL | ||||
|             || key == NULL | ||||
|             || key->keylen != ecxctx->keylen | ||||
|             || !ecx_key_up_ref(key)) { | ||||
|         ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     ecx_key_free(ecxctx->key); | ||||
|     ecxctx->key = key; | ||||
| 
 | ||||
|     return 1; | ||||
| } | ||||
| 
 | ||||
| static int ecx_set_peer(void *vecxctx, void *vkey) | ||||
| { | ||||
|     PROV_ECX_CTX *ecxctx = (PROV_ECX_CTX *)vecxctx; | ||||
|     ECX_KEY *key = vkey; | ||||
| 
 | ||||
|     if (ecxctx == NULL | ||||
|             || key == NULL | ||||
|             || key->keylen != ecxctx->keylen | ||||
|             || !ecx_key_up_ref(key)) { | ||||
|         ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); | ||||
|         return 0; | ||||
|     } | ||||
|     ecx_key_free(ecxctx->peerkey); | ||||
|     ecxctx->peerkey = key; | ||||
| 
 | ||||
|     return 1; | ||||
| } | ||||
| 
 | ||||
| static int ecx_derive(void *vecxctx, unsigned char *secret, size_t *secretlen, | ||||
|                       size_t outlen) | ||||
| { | ||||
|     PROV_ECX_CTX *ecxctx = (PROV_ECX_CTX *)vecxctx; | ||||
| 
 | ||||
|     if (ecxctx->key == NULL | ||||
|             || ecxctx->key->privkey == NULL | ||||
|             || ecxctx->peerkey == NULL) { | ||||
|         ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     if (!ossl_assert(ecxctx->keylen == X25519_KEYLEN | ||||
|             || ecxctx->keylen == X448_KEYLEN)) { | ||||
|         ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     if (secret == NULL) { | ||||
|         *secretlen = ecxctx->keylen; | ||||
|         return 1; | ||||
|     } | ||||
|     if (outlen < ecxctx->keylen) { | ||||
|         ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     if (ecxctx->keylen == X25519_KEYLEN) { | ||||
|         if (X25519(secret, ecxctx->key->privkey, ecxctx->peerkey->pubkey) == 0) { | ||||
|             ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_DURING_DERIVATION); | ||||
|             return 0; | ||||
|         } | ||||
|     } else { | ||||
|         if (X448(secret, ecxctx->key->privkey, ecxctx->peerkey->pubkey) == 0) { | ||||
|             ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_DURING_DERIVATION); | ||||
|             return 0; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     *secretlen = ecxctx->keylen; | ||||
|     return 1; | ||||
| } | ||||
| 
 | ||||
| static void ecx_freectx(void *vecxctx) | ||||
| { | ||||
|     PROV_ECX_CTX *ecxctx = (PROV_ECX_CTX *)vecxctx; | ||||
| 
 | ||||
|     ecx_key_free(ecxctx->key); | ||||
|     ecx_key_free(ecxctx->peerkey); | ||||
| 
 | ||||
|     OPENSSL_free(ecxctx); | ||||
| } | ||||
| 
 | ||||
| static void *ecx_dupctx(void *vecxctx) | ||||
| { | ||||
|     PROV_ECX_CTX *srcctx = (PROV_ECX_CTX *)vecxctx; | ||||
|     PROV_ECX_CTX *dstctx; | ||||
| 
 | ||||
|     dstctx = OPENSSL_zalloc(sizeof(*srcctx)); | ||||
|     if (dstctx == NULL) { | ||||
|         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     *dstctx = *srcctx; | ||||
|     if (dstctx->key != NULL && !ecx_key_up_ref(dstctx->key)) { | ||||
|         ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); | ||||
|         OPENSSL_free(dstctx); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     if (dstctx->peerkey != NULL && !ecx_key_up_ref(dstctx->peerkey)) { | ||||
|         ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); | ||||
|         ecx_key_free(dstctx->key); | ||||
|         OPENSSL_free(dstctx); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     return dstctx; | ||||
| } | ||||
| 
 | ||||
| const OSSL_DISPATCH x25519_keyexch_functions[] = { | ||||
|     { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))x25519_newctx }, | ||||
|     { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))ecx_init }, | ||||
|     { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))ecx_derive }, | ||||
|     { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))ecx_set_peer }, | ||||
|     { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))ecx_freectx }, | ||||
|     { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))ecx_dupctx }, | ||||
|     { 0, NULL } | ||||
| }; | ||||
| 
 | ||||
| const OSSL_DISPATCH x448_keyexch_functions[] = { | ||||
|     { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))x448_newctx }, | ||||
|     { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))ecx_init }, | ||||
|     { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))ecx_derive }, | ||||
|     { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))ecx_set_peer }, | ||||
|     { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))ecx_freectx }, | ||||
|     { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))ecx_dupctx }, | ||||
|     { 0, NULL } | ||||
| }; | ||||
|  | @ -262,6 +262,8 @@ extern const OSSL_DISPATCH x448_keymgmt_functions[]; | |||
| 
 | ||||
| /* Key Exchange */ | ||||
| extern const OSSL_DISPATCH dh_keyexch_functions[]; | ||||
| extern const OSSL_DISPATCH x25519_keyexch_functions[]; | ||||
| extern const OSSL_DISPATCH x448_keyexch_functions[]; | ||||
| 
 | ||||
| /* Signature */ | ||||
| extern const OSSL_DISPATCH dsa_signature_functions[]; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue