From 3965480c824c9823db7803cc1a403be863cecc00 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 5 Mar 2020 15:42:13 +0000 Subject: [PATCH] Implement provider support for Ed25519 annd Ed448 At the moment we only provider support for these algorithms in the default provider. These algorithms only support "one shot" EVP_DigestSign() and EVP_DigestVerify() as per the existing libcrypto versions. Reviewed-by: Shane Lontis (Merged from https://github.com/openssl/openssl/pull/11261) --- crypto/ec/curve448/curve448_local.h | 9 - crypto/ec/curve448/eddsa.c | 1 + crypto/ec/ec_local.h | 4 - crypto/ec/ecx_meth.c | 4 + crypto/err/openssl.txt | 1 + crypto/evp/evp_local.h | 2 + include/crypto/ecx.h | 14 ++ .../common/include/prov/providercommonerr.h | 1 + providers/common/provider_err.c | 1 + providers/defltprov.c | 4 + .../include/prov/implementations.h | 2 + .../implementations/signature/build.info | 5 + providers/implementations/signature/eddsa.c | 211 ++++++++++++++++++ 13 files changed, 246 insertions(+), 13 deletions(-) create mode 100644 providers/implementations/signature/eddsa.c diff --git a/crypto/ec/curve448/curve448_local.h b/crypto/ec/curve448/curve448_local.h index 36f960ec0e..b70a1b5406 100644 --- a/crypto/ec/curve448/curve448_local.h +++ b/crypto/ec/curve448/curve448_local.h @@ -10,15 +10,6 @@ # define OSSL_CRYPTO_EC_CURVE448_LOCAL_H # include "curve448utils.h" -int ED448_sign(OPENSSL_CTX *ctx, uint8_t *out_sig, const uint8_t *message, - size_t message_len, const uint8_t public_key[57], - const uint8_t private_key[57], const uint8_t *context, - size_t context_len); - -int ED448_verify(OPENSSL_CTX *ctx, const uint8_t *message, size_t message_len, - const uint8_t signature[114], const uint8_t public_key[57], - const uint8_t *context, size_t context_len); - int ED448ph_sign(OPENSSL_CTX *ctx, uint8_t *out_sig, const uint8_t hash[64], const uint8_t public_key[57], const uint8_t private_key[57], const uint8_t *context, size_t context_len); diff --git a/crypto/ec/curve448/eddsa.c b/crypto/ec/curve448/eddsa.c index b5762cb584..1cd76844d9 100644 --- a/crypto/ec/curve448/eddsa.c +++ b/crypto/ec/curve448/eddsa.c @@ -12,6 +12,7 @@ #include #include #include +#include "crypto/ecx.h" #include "curve448_local.h" #include "word.h" #include "ed448.h" diff --git a/crypto/ec/ec_local.h b/crypto/ec/ec_local.h index dacb2ca0af..b5963a7e5f 100644 --- a/crypto/ec/ec_local.h +++ b/crypto/ec/ec_local.h @@ -679,10 +679,6 @@ ECDSA_SIG *ecdsa_simple_sign_sig(const unsigned char *dgst, int dgst_len, int ecdsa_simple_verify_sig(const unsigned char *dgst, int dgst_len, const ECDSA_SIG *sig, EC_KEY *eckey); -int ED25519_sign(uint8_t *out_sig, const uint8_t *message, size_t message_len, - const uint8_t public_key[32], const uint8_t private_key[32]); -int ED25519_verify(const uint8_t *message, size_t message_len, - const uint8_t signature[64], const uint8_t public_key[32]); void ED25519_public_from_private(uint8_t out_public_key[32], const uint8_t private_key[32]); diff --git a/crypto/ec/ecx_meth.c b/crypto/ec/ecx_meth.c index 32817562bf..f107df3aa4 100644 --- a/crypto/ec/ecx_meth.c +++ b/crypto/ec/ecx_meth.c @@ -648,6 +648,8 @@ const EVP_PKEY_ASN1_METHOD ed25519_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 ed448_asn1_meth = { @@ -690,6 +692,8 @@ const EVP_PKEY_ASN1_METHOD ed448_asn1_meth = { ecx_set_pub_key, ecx_get_priv_key, ecx_get_pub_key, + ecx_pkey_dirty_cnt, + ecx_pkey_export_to }; static int pkey_ecx_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index f14acc65b6..8689e34925 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -2773,6 +2773,7 @@ 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 PROV_R_FAILED_TO_SET_PARAMETER:104:failed to set parameter +PROV_R_FAILED_TO_SIGN:175:failed to sign PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE:165:\ illegal or unsupported padding mode PROV_R_INAVLID_UKM_LENGTH:146:inavlid ukm length diff --git a/crypto/evp/evp_local.h b/crypto/evp/evp_local.h index 774db4da8f..858f1c49d6 100644 --- a/crypto/evp/evp_local.h +++ b/crypto/evp/evp_local.h @@ -129,9 +129,11 @@ struct evp_signature_st { OSSL_OP_signature_digest_sign_init_fn *digest_sign_init; OSSL_OP_signature_digest_sign_update_fn *digest_sign_update; OSSL_OP_signature_digest_sign_final_fn *digest_sign_final; + OSSL_OP_signature_digest_sign_fn *digest_sign; OSSL_OP_signature_digest_verify_init_fn *digest_verify_init; OSSL_OP_signature_digest_verify_update_fn *digest_verify_update; OSSL_OP_signature_digest_verify_final_fn *digest_verify_final; + OSSL_OP_signature_digest_verify_fn *digest_verify; OSSL_OP_signature_freectx_fn *freectx; OSSL_OP_signature_dupctx_fn *dupctx; OSSL_OP_signature_get_ctx_params_fn *get_ctx_params; diff --git a/include/crypto/ecx.h b/include/crypto/ecx.h index 6753e14cb2..3e494bf092 100644 --- a/include/crypto/ecx.h +++ b/include/crypto/ecx.h @@ -63,6 +63,20 @@ int X25519(uint8_t out_shared_key[32], const uint8_t private_key[32], void X25519_public_from_private(uint8_t out_public_value[32], const uint8_t private_key[32]); +int ED25519_sign(uint8_t *out_sig, const uint8_t *message, size_t message_len, + const uint8_t public_key[32], const uint8_t private_key[32]); +int ED25519_verify(const uint8_t *message, size_t message_len, + const uint8_t signature[64], const uint8_t public_key[32]); + +int ED448_sign(OPENSSL_CTX *ctx, uint8_t *out_sig, const uint8_t *message, + size_t message_len, const uint8_t public_key[57], + const uint8_t private_key[57], const uint8_t *context, + size_t context_len); + +int ED448_verify(OPENSSL_CTX *ctx, const uint8_t *message, size_t message_len, + const uint8_t signature[114], const uint8_t public_key[57], + const uint8_t *context, size_t context_len); + int X448(uint8_t out_shared_key[56], const uint8_t private_key[56], const uint8_t peer_public_value[56]); void X448_public_from_private(uint8_t out_public_value[56], diff --git a/providers/common/include/prov/providercommonerr.h b/providers/common/include/prov/providercommonerr.h index 19ecab1f0f..f834a71347 100644 --- a/providers/common/include/prov/providercommonerr.h +++ b/providers/common/include/prov/providercommonerr.h @@ -64,6 +64,7 @@ int ERR_load_PROV_strings(void); # define PROV_R_FAILED_TO_GENERATE_KEY 121 # define PROV_R_FAILED_TO_GET_PARAMETER 103 # define PROV_R_FAILED_TO_SET_PARAMETER 104 +# define PROV_R_FAILED_TO_SIGN 175 # define PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE 165 # define PROV_R_INAVLID_UKM_LENGTH 146 # define PROV_R_INVALID_AAD 108 diff --git a/providers/common/provider_err.c b/providers/common/provider_err.c index f73f82351f..1a65e2cc87 100644 --- a/providers/common/provider_err.c +++ b/providers/common/provider_err.c @@ -39,6 +39,7 @@ static const ERR_STRING_DATA PROV_str_reasons[] = { "failed to get parameter"}, {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_FAILED_TO_SET_PARAMETER), "failed to set parameter"}, + {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_FAILED_TO_SIGN), "failed to sign"}, {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE), "illegal or unsupported padding mode"}, {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INAVLID_UKM_LENGTH), diff --git a/providers/defltprov.c b/providers/defltprov.c index a410eea13d..7bb23e300e 100644 --- a/providers/defltprov.c +++ b/providers/defltprov.c @@ -385,6 +385,10 @@ static const OSSL_ALGORITHM deflt_signature[] = { { "DSA:dsaEncryption", "provider=default", dsa_signature_functions }, #endif { "RSA:rsaEncryption", "provider=default", rsa_signature_functions }, +#ifndef OPENSSL_NO_EC + { "ED25519:Ed25519", "provider=default", ed25519_signature_functions }, + { "ED448:Ed448", "provider=default", ed448_signature_functions }, +#endif { NULL, NULL, NULL } }; diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h index e3afa987d6..94265adfc2 100644 --- a/providers/implementations/include/prov/implementations.h +++ b/providers/implementations/include/prov/implementations.h @@ -272,6 +272,8 @@ extern const OSSL_DISPATCH ecdh_keyexch_functions[]; /* Signature */ extern const OSSL_DISPATCH dsa_signature_functions[]; extern const OSSL_DISPATCH rsa_signature_functions[]; +extern const OSSL_DISPATCH ed25519_signature_functions[]; +extern const OSSL_DISPATCH ed448_signature_functions[]; /* Asym Cipher */ extern const OSSL_DISPATCH rsa_asym_cipher_functions[]; diff --git a/providers/implementations/signature/build.info b/providers/implementations/signature/build.info index 22b55dcf54..c5d0645a8a 100644 --- a/providers/implementations/signature/build.info +++ b/providers/implementations/signature/build.info @@ -3,11 +3,16 @@ $DSA_GOAL=../../libimplementations.a $RSA_GOAL=../../libimplementations.a +$EC_GOAL=../../libimplementations.a IF[{- !$disabled{dsa} -}] SOURCE[$DSA_GOAL]=dsa.c ENDIF +IF[{- !$disabled{ec} -}] + SOURCE[$EC_GOAL]=eddsa.c +ENDIF + SOURCE[$RSA_GOAL]=rsa.c diff --git a/providers/implementations/signature/eddsa.c b/providers/implementations/signature/eddsa.c new file mode 100644 index 0000000000..d2444f9e36 --- /dev/null +++ b/providers/implementations/signature/eddsa.c @@ -0,0 +1,211 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include "internal/nelem.h" +#include "internal/sizes.h" +#include "prov/providercommonerr.h" +#include "prov/implementations.h" +#include "prov/providercommonerr.h" +#include "prov/provider_ctx.h" +#include "crypto/ecx.h" + +static OSSL_OP_signature_newctx_fn eddsa_newctx; +static OSSL_OP_signature_digest_sign_init_fn eddsa_digest_signverify_init; +static OSSL_OP_signature_digest_sign_fn ed25519_digest_sign; +static OSSL_OP_signature_digest_sign_fn ed448_digest_sign; +static OSSL_OP_signature_digest_verify_fn ed25519_digest_verify; +static OSSL_OP_signature_digest_verify_fn ed448_digest_verify; +static OSSL_OP_signature_freectx_fn eddsa_freectx; +static OSSL_OP_signature_dupctx_fn eddsa_dupctx; + +typedef struct { + OPENSSL_CTX *libctx; + ECX_KEY *key; +} PROV_EDDSA_CTX; + +static void *eddsa_newctx(void *provctx) +{ + PROV_EDDSA_CTX *peddsactx = OPENSSL_zalloc(sizeof(PROV_EDDSA_CTX)); + + if (peddsactx == NULL) { + PROVerr(0, ERR_R_MALLOC_FAILURE); + return NULL; + } + + peddsactx->libctx = PROV_LIBRARY_CONTEXT_OF(provctx); + + return peddsactx; +} + +static int eddsa_digest_signverify_init(void *vpeddsactx, const char *mdname, + const char *props, void *vedkey) +{ + PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx; + ECX_KEY *edkey = (ECX_KEY *)vedkey; + + if (mdname != NULL) { + PROVerr(0, PROV_R_INVALID_DIGEST); + return 0; + } + + if (!ecx_key_up_ref(edkey)) { + PROVerr(0, ERR_R_INTERNAL_ERROR); + return 0; + } + + peddsactx->key = edkey; + + return 1; +} + +int ed25519_digest_sign(void *vpeddsactx, unsigned char *sigret, + size_t *siglen, size_t sigsize, + const unsigned char *tbs, size_t tbslen) +{ + PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx; + const ECX_KEY *edkey = peddsactx->key; + + if (sigret == NULL) { + *siglen = ED25519_SIGSIZE; + return 1; + } + if (sigsize < ED25519_SIGSIZE) { + PROVerr(0, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (ED25519_sign(sigret, tbs, tbslen, edkey->pubkey, edkey->privkey) == 0) { + PROVerr(0, PROV_R_FAILED_TO_SIGN); + return 0; + } + *siglen = ED25519_SIGSIZE; + return 1; +} + +int ed448_digest_sign(void *vpeddsactx, unsigned char *sigret, + size_t *siglen, size_t sigsize, + const unsigned char *tbs, size_t tbslen) +{ + PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx; + const ECX_KEY *edkey = peddsactx->key; + + if (sigret == NULL) { + *siglen = ED448_SIGSIZE; + return 1; + } + if (sigsize < ED448_SIGSIZE) { + PROVerr(0, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (ED448_sign(peddsactx->libctx, sigret, tbs, tbslen, edkey->pubkey, + edkey->privkey, NULL, 0) == 0) { + PROVerr(0, PROV_R_FAILED_TO_SIGN); + return 0; + } + *siglen = ED448_SIGSIZE; + return 1; +} + +int ed25519_digest_verify(void *vpeddsactx, const unsigned char *sig, + size_t siglen, const unsigned char *tbs, + size_t tbslen) +{ + PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx; + const ECX_KEY *edkey = peddsactx->key; + + if (siglen != ED25519_SIGSIZE) + return 0; + + return ED25519_verify(tbs, tbslen, sig, edkey->pubkey); +} + +int ed448_digest_verify(void *vpeddsactx, const unsigned char *sig, + size_t siglen, const unsigned char *tbs, + size_t tbslen) +{ + PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx; + const ECX_KEY *edkey = peddsactx->key; + + if (siglen != ED448_SIGSIZE) + return 0; + + return ED448_verify(peddsactx->libctx, tbs, tbslen, sig, edkey->pubkey, + NULL, 0); +} + +static void eddsa_freectx(void *vpeddsactx) +{ + PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx; + + ecx_key_free(peddsactx->key); + + OPENSSL_free(peddsactx); +} + +static void *eddsa_dupctx(void *vpeddsactx) +{ + PROV_EDDSA_CTX *srcctx = (PROV_EDDSA_CTX *)vpeddsactx; + PROV_EDDSA_CTX *dstctx; + + dstctx = OPENSSL_zalloc(sizeof(*srcctx)); + if (dstctx == NULL) + return NULL; + + *dstctx = *srcctx; + dstctx->key = NULL; + + if (srcctx->key != NULL && !ecx_key_up_ref(srcctx->key)) { + PROVerr(0, ERR_R_INTERNAL_ERROR); + goto err; + } + dstctx->key = srcctx->key; + + return dstctx; + err: + eddsa_freectx(dstctx); + return NULL; +} + +const OSSL_DISPATCH ed25519_signature_functions[] = { + { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))eddsa_newctx }, + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, + (void (*)(void))eddsa_digest_signverify_init }, + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN, + (void (*)(void))ed25519_digest_sign }, + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, + (void (*)(void))eddsa_digest_signverify_init }, + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY, + (void (*)(void))ed25519_digest_verify }, + { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))eddsa_freectx }, + { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))eddsa_dupctx }, + { 0, NULL } +}; + +const OSSL_DISPATCH ed448_signature_functions[] = { + { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))eddsa_newctx }, + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, + (void (*)(void))eddsa_digest_signverify_init }, + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN, + (void (*)(void))ed448_digest_sign }, + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, + (void (*)(void))eddsa_digest_signverify_init }, + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY, + (void (*)(void))ed448_digest_verify }, + { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))eddsa_freectx }, + { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))eddsa_dupctx }, + { 0, NULL } +}; -- 2.34.1