/*
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