/* This file is part of TON Blockchain Library. TON Blockchain Library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. TON Blockchain Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . */ #include "p256.h" #include "td/utils/check.h" #include "td/utils/misc.h" #include #include #include namespace td { td::Status p256_check_signature(td::Slice data, td::Slice public_key, td::Slice signature) { CHECK(public_key.size() == 33); CHECK(signature.size() == 64); EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr); if (pctx == nullptr) { return td::Status::Error("Can't create EVP_PKEY_CTX"); } SCOPE_EXIT { EVP_PKEY_CTX_free(pctx); }; if (EVP_PKEY_paramgen_init(pctx) <= 0) { return td::Status::Error("EVP_PKEY_paramgen_init failed"); } if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1) <= 0) { return td::Status::Error("EVP_PKEY_CTX_set_ec_paramgen_curve_nid failed"); } EVP_PKEY* pkey = nullptr; if (EVP_PKEY_paramgen(pctx, &pkey) <= 0) { return td::Status::Error("EVP_PKEY_paramgen failed"); } SCOPE_EXIT { EVP_PKEY_free(pkey); }; if (EVP_PKEY_set1_tls_encodedpoint(pkey, public_key.ubegin(), public_key.size()) <= 0) { return td::Status::Error("Failed to import public key"); } EVP_MD_CTX* md_ctx = EVP_MD_CTX_new(); if (md_ctx == nullptr) { return td::Status::Error("Can't create EVP_MD_CTX"); } SCOPE_EXIT { EVP_MD_CTX_free(md_ctx); }; if (EVP_DigestVerifyInit(md_ctx, nullptr, nullptr, nullptr, pkey) <= 0) { return td::Status::Error("Can't init DigestVerify"); } ECDSA_SIG* sig = ECDSA_SIG_new(); SCOPE_EXIT { ECDSA_SIG_free(sig); }; unsigned char buf[33]; buf[0] = 0; std::copy(signature.ubegin(), signature.ubegin() + 32, buf + 1); BIGNUM* r = BN_bin2bn(buf, 33, nullptr); std::copy(signature.ubegin() + 32, signature.ubegin() + 64, buf + 1); BIGNUM* s = BN_bin2bn(buf, 33, nullptr); if (ECDSA_SIG_set0(sig, r, s) != 1) { return td::Status::Error("Invalid signature"); } unsigned char* signature_encoded = nullptr; int signature_len = i2d_ECDSA_SIG(sig, &signature_encoded); if (signature_len <= 0) { return td::Status::Error("Invalid signature"); } SCOPE_EXIT { OPENSSL_free(signature_encoded); }; if (EVP_DigestVerify(md_ctx, signature_encoded, signature_len, data.ubegin(), data.size()) == 1) { return td::Status::OK(); } return td::Status::Error("Wrong signature"); } } // namespace td