| // Copyright 2006-2016 The OpenSSL Project Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include <openssl/evp.h> |
| |
| #include <string.h> |
| |
| #include <openssl/digest.h> |
| #include <openssl/err.h> |
| #include <openssl/mem.h> |
| |
| #include "../internal.h" |
| #include "../mem_internal.h" |
| #include "internal.h" |
| |
| |
| using namespace bssl; |
| |
| // |EVP_PKEY_RSA_PSS| is intentionally omitted from this list. These are types |
| // that can be created without an |EVP_PKEY|, and we do not support |
| // |EVP_PKEY_RSA_PSS| keygen. |
| static const EVP_PKEY_CTX_METHOD *const evp_methods[] = { |
| &rsa_pkey_meth, &ec_pkey_meth, &ed25519_pkey_meth, |
| &x25519_pkey_meth, &hkdf_pkey_meth, |
| }; |
| |
| static const EVP_PKEY_CTX_METHOD *evp_pkey_meth_find(int type) { |
| for (auto method : evp_methods) { |
| if (method->pkey_id == type) { |
| return method; |
| } |
| } |
| |
| return nullptr; |
| } |
| |
| static EvpPkeyCtx *evp_pkey_ctx_new(EvpPkey *pkey, |
| const EVP_PKEY_CTX_METHOD *pmeth) { |
| UniquePtr<EvpPkeyCtx> ret = MakeUnique<EvpPkeyCtx>(); |
| if (!ret) { |
| return nullptr; |
| } |
| |
| ret->pmeth = pmeth; |
| ret->operation = EVP_PKEY_OP_UNDEFINED; |
| ret->pkey = UpRef(pkey); |
| |
| if (pmeth->init && pmeth->init(ret.get()) <= 0) { |
| ret->pmeth = nullptr; // Don't call |pmeth->cleanup|. |
| return nullptr; |
| } |
| |
| return ret.release(); |
| } |
| |
| EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e) { |
| auto *impl = FromOpaque(pkey); |
| if (impl == nullptr || impl->ameth == nullptr) { |
| OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER); |
| return nullptr; |
| } |
| |
| const EVP_PKEY_CTX_METHOD *pkey_method = impl->ameth->pkey_method; |
| if (pkey_method == nullptr) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); |
| ERR_add_error_dataf("algorithm %d", impl->ameth->pkey_id); |
| return nullptr; |
| } |
| |
| return evp_pkey_ctx_new(impl, pkey_method); |
| } |
| |
| EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e) { |
| const EVP_PKEY_CTX_METHOD *pkey_method = evp_pkey_meth_find(id); |
| if (pkey_method == nullptr) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); |
| ERR_add_error_dataf("algorithm %d", id); |
| return nullptr; |
| } |
| |
| return evp_pkey_ctx_new(nullptr, pkey_method); |
| } |
| |
| EvpPkeyCtx::~EvpPkeyCtx() { |
| if (pmeth && pmeth->cleanup) { |
| pmeth->cleanup(this); |
| } |
| } |
| |
| void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx) { Delete(FromOpaque(ctx)); } |
| |
| EVP_PKEY_CTX *EVP_PKEY_CTX_dup(EVP_PKEY_CTX *ctx) { |
| auto *impl = FromOpaque(ctx); |
| |
| if (!impl->pmeth || !impl->pmeth->copy) { |
| return nullptr; |
| } |
| |
| UniquePtr<EvpPkeyCtx> ret = MakeUnique<EvpPkeyCtx>(); |
| if (!ret) { |
| return nullptr; |
| } |
| |
| ret->pmeth = impl->pmeth; |
| ret->operation = impl->operation; |
| ret->pkey = UpRef(impl->pkey); |
| ret->peerkey = UpRef(impl->peerkey); |
| if (impl->pmeth->copy(ret.get(), impl) <= 0) { |
| ret->pmeth = nullptr; // Don't call |pmeth->cleanup|. |
| OPENSSL_PUT_ERROR(EVP, ERR_LIB_EVP); |
| return nullptr; |
| } |
| |
| return ret.release(); |
| } |
| |
| EVP_PKEY *EVP_PKEY_CTX_get0_pkey(EVP_PKEY_CTX *ctx) { |
| auto *impl = FromOpaque(ctx); |
| return impl->pkey.get(); |
| } |
| |
| int bssl::EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype, int cmd, |
| int p1, void *p2) { |
| auto *impl = FromOpaque(ctx); |
| if (!impl || !impl->pmeth || !impl->pmeth->ctrl) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED); |
| return 0; |
| } |
| if (keytype != -1 && impl->pmeth->pkey_id != keytype) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
| return 0; |
| } |
| |
| if (impl->operation == EVP_PKEY_OP_UNDEFINED) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_NO_OPERATION_SET); |
| return 0; |
| } |
| |
| if (optype != -1 && !(impl->operation & optype)) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION); |
| return 0; |
| } |
| |
| return impl->pmeth->ctrl(impl, cmd, p1, p2); |
| } |
| |
| int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx) { |
| auto *impl = FromOpaque(ctx); |
| if (!ctx || impl->pmeth == nullptr || |
| (impl->pmeth->sign == nullptr && impl->pmeth->sign_message == nullptr)) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
| return 0; |
| } |
| |
| impl->operation = EVP_PKEY_OP_SIGN; |
| return 1; |
| } |
| |
| int EVP_PKEY_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *sig_len, |
| const uint8_t *digest, size_t digest_len) { |
| auto *impl = FromOpaque(ctx); |
| if (!impl || !impl->pmeth || !impl->pmeth->sign) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
| return 0; |
| } |
| if (impl->operation != EVP_PKEY_OP_SIGN) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); |
| return 0; |
| } |
| return impl->pmeth->sign(impl, sig, sig_len, digest, digest_len); |
| } |
| |
| int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx) { |
| auto *impl = FromOpaque(ctx); |
| if (!impl || impl->pmeth == nullptr || |
| (impl->pmeth->verify == nullptr && |
| impl->pmeth->verify_message == nullptr)) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
| return 0; |
| } |
| impl->operation = EVP_PKEY_OP_VERIFY; |
| return 1; |
| } |
| |
| int EVP_PKEY_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t sig_len, |
| const uint8_t *digest, size_t digest_len) { |
| auto *impl = FromOpaque(ctx); |
| if (!impl || !impl->pmeth || !impl->pmeth->verify) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
| return 0; |
| } |
| if (impl->operation != EVP_PKEY_OP_VERIFY) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); |
| return 0; |
| } |
| return impl->pmeth->verify(impl, sig, sig_len, digest, digest_len); |
| } |
| |
| int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx) { |
| auto *impl = FromOpaque(ctx); |
| if (!impl || !impl->pmeth || !impl->pmeth->encrypt) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
| return 0; |
| } |
| impl->operation = EVP_PKEY_OP_ENCRYPT; |
| return 1; |
| } |
| |
| int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen, |
| const uint8_t *in, size_t inlen) { |
| auto *impl = FromOpaque(ctx); |
| if (!impl || !impl->pmeth || !impl->pmeth->encrypt) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
| return 0; |
| } |
| if (impl->operation != EVP_PKEY_OP_ENCRYPT) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); |
| return 0; |
| } |
| return impl->pmeth->encrypt(impl, out, outlen, in, inlen); |
| } |
| |
| int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *ctx) { |
| auto *impl = FromOpaque(ctx); |
| if (!impl || !impl->pmeth || !impl->pmeth->decrypt) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
| return 0; |
| } |
| impl->operation = EVP_PKEY_OP_DECRYPT; |
| return 1; |
| } |
| |
| int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen, |
| const uint8_t *in, size_t inlen) { |
| auto *impl = FromOpaque(ctx); |
| if (!impl || !impl->pmeth || !impl->pmeth->decrypt) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
| return 0; |
| } |
| if (impl->operation != EVP_PKEY_OP_DECRYPT) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); |
| return 0; |
| } |
| return impl->pmeth->decrypt(impl, out, outlen, in, inlen); |
| } |
| |
| int EVP_PKEY_verify_recover_init(EVP_PKEY_CTX *ctx) { |
| auto *impl = FromOpaque(ctx); |
| if (!impl || !impl->pmeth || !impl->pmeth->verify_recover) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
| return 0; |
| } |
| impl->operation = EVP_PKEY_OP_VERIFYRECOVER; |
| return 1; |
| } |
| |
| int EVP_PKEY_verify_recover(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *out_len, |
| const uint8_t *sig, size_t sig_len) { |
| auto *impl = FromOpaque(ctx); |
| if (!impl || !impl->pmeth || !impl->pmeth->verify_recover) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
| return 0; |
| } |
| if (impl->operation != EVP_PKEY_OP_VERIFYRECOVER) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); |
| return 0; |
| } |
| return impl->pmeth->verify_recover(impl, out, out_len, sig, sig_len); |
| } |
| |
| int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx) { |
| auto *impl = FromOpaque(ctx); |
| if (!impl || !impl->pmeth || !impl->pmeth->derive) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
| return 0; |
| } |
| impl->operation = EVP_PKEY_OP_DERIVE; |
| return 1; |
| } |
| |
| int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer) { |
| auto *impl = FromOpaque(ctx); |
| if (!impl || !impl->pmeth || |
| !(impl->pmeth->derive || impl->pmeth->encrypt || impl->pmeth->decrypt) || |
| !impl->pmeth->ctrl) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
| return 0; |
| } |
| if (impl->operation != EVP_PKEY_OP_DERIVE && |
| impl->operation != EVP_PKEY_OP_ENCRYPT && |
| impl->operation != EVP_PKEY_OP_DECRYPT) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); |
| return 0; |
| } |
| |
| int ret = impl->pmeth->ctrl(impl, EVP_PKEY_CTRL_PEER_KEY, 0, peer); |
| |
| if (ret <= 0) { |
| return 0; |
| } |
| |
| if (ret == 2) { |
| return 1; |
| } |
| |
| if (!impl->pkey) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET); |
| return 0; |
| } |
| |
| if (EVP_PKEY_id(impl->pkey.get()) != EVP_PKEY_id(peer)) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_KEY_TYPES); |
| return 0; |
| } |
| |
| // ran@cryptocom.ru: For clarity. The error is if parameters in peer are |
| // present (!missing) but don't match. EVP_PKEY_cmp_parameters may return |
| // 1 (match), 0 (don't match) and -2 (comparison is not defined). -1 |
| // (different key types) is impossible here because it is checked earlier. |
| // -2 is OK for us here, as well as 1, so we can check for 0 only. |
| if (!EVP_PKEY_missing_parameters(peer) && |
| !EVP_PKEY_cmp_parameters(impl->pkey.get(), peer)) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_PARAMETERS); |
| return 0; |
| } |
| |
| impl->peerkey = UpRef(FromOpaque(peer)); |
| ret = impl->pmeth->ctrl(impl, EVP_PKEY_CTRL_PEER_KEY, 1, peer); |
| if (ret <= 0) { |
| impl->peerkey = nullptr; |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, uint8_t *key, size_t *out_key_len) { |
| auto *impl = FromOpaque(ctx); |
| if (!impl || !impl->pmeth || !impl->pmeth->derive) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
| return 0; |
| } |
| if (impl->operation != EVP_PKEY_OP_DERIVE) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); |
| return 0; |
| } |
| return impl->pmeth->derive(impl, key, out_key_len); |
| } |
| |
| int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx) { |
| auto *impl = FromOpaque(ctx); |
| if (!impl || !impl->pmeth || !impl->pmeth->keygen) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
| return 0; |
| } |
| impl->operation = EVP_PKEY_OP_KEYGEN; |
| return 1; |
| } |
| |
| int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **out_pkey) { |
| auto *impl = FromOpaque(ctx); |
| if (!impl || !impl->pmeth || !impl->pmeth->keygen) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
| return 0; |
| } |
| if (impl->operation != EVP_PKEY_OP_KEYGEN) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); |
| return 0; |
| } |
| |
| if (!out_pkey) { |
| return 0; |
| } |
| |
| if (!*out_pkey) { |
| *out_pkey = EVP_PKEY_new(); |
| if (!*out_pkey) { |
| OPENSSL_PUT_ERROR(EVP, ERR_LIB_EVP); |
| return 0; |
| } |
| } |
| |
| if (!impl->pmeth->keygen(impl, FromOpaque(*out_pkey))) { |
| EVP_PKEY_free(*out_pkey); |
| *out_pkey = nullptr; |
| return 0; |
| } |
| return 1; |
| } |
| |
| int EVP_PKEY_paramgen_init(EVP_PKEY_CTX *ctx) { |
| auto *impl = FromOpaque(ctx); |
| if (!impl || !impl->pmeth || !impl->pmeth->paramgen) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
| return 0; |
| } |
| impl->operation = EVP_PKEY_OP_PARAMGEN; |
| return 1; |
| } |
| |
| int EVP_PKEY_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY **out_pkey) { |
| auto *impl = FromOpaque(ctx); |
| if (!impl || !impl->pmeth || !impl->pmeth->paramgen) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
| return 0; |
| } |
| if (impl->operation != EVP_PKEY_OP_PARAMGEN) { |
| OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); |
| return 0; |
| } |
| |
| if (!out_pkey) { |
| return 0; |
| } |
| |
| if (!*out_pkey) { |
| *out_pkey = EVP_PKEY_new(); |
| if (!*out_pkey) { |
| OPENSSL_PUT_ERROR(EVP, ERR_LIB_EVP); |
| return 0; |
| } |
| } |
| |
| if (!impl->pmeth->paramgen(impl, FromOpaque(*out_pkey))) { |
| EVP_PKEY_free(*out_pkey); |
| *out_pkey = nullptr; |
| return 0; |
| } |
| return 1; |
| } |