如何解决在由 ECDSA_do_verify 生成的 signature->r 或 signature-s 上,BN_bn2bin 的结果大小有时是 31 而不是 32
我使用 openssl 为 Apple 令牌端点生成 client_secret(JWT)。我发现帖子 https://developer.apple.com/forums/thread/123723 说我们应该解析 R、S 值并连接这两个值。
我使用以下代码为 client_secret 生成签名:
#include <string>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/pem.h>
#include <openssl/ec.h>
#include <openssl/err.h>
using namespace std;
class ECDSA256
{
public:
ECDSA256(const string& private_key) : is_error_(false),err_str_(""),private_key_(NULL),private_key_bio_(NULL),evp_md_ctx_(NULL),ecdsa_sig_(NULL)
{
private_key_bio_ = BIO_new(BIO_s_mem());
if ((size_t)BIO_write(private_key_bio_,private_key.data(),private_key.size()) != private_key.size())
{
is_error_ = true;
err_str_.append("failed to load private key: BIO_wirte failed\n");
return;
}
private_key_ = PEM_read_bio_ECPrivateKey(private_key_bio_,NULL,NULL);
if (!private_key_)
{
is_error_ = true;
err_str_.append("failed to load private key: PEM_read_bio_ECPrivateKey failed\n");
return;
}
if (0 == EC_KEY_check_key(private_key_))
{
is_error_ = true;
err_str_.append("failed to load private key: EC_KEY_check_key failed\n");
return;
}
}
virtual ~ECDSA256()
{
clear();
}
string sign(const string& data)
{
const string hashed = hash(data);
if (is_error_)
{
return "";
}
ecdsa_sig_ = ECDSA_do_sign((const unsigned char*)hashed.data(),hashed.size(),private_key_);
if (!ecdsa_sig_)
{
is_error_ = true;
err_str_.append("ECDSA_do_sign failed\n");
return "";
}
return bn2raw(ecdsa_sig_->r) + bn2raw(ecdsa_sig_->s);
}
void clear()
{
if (private_key_bio_)
{
BIO_free_all(private_key_bio_);
private_key_bio_ = NULL;
}
if (private_key_)
{
EC_KEY_free(private_key_);
private_key_ = NULL;
}
if (evp_md_ctx_)
{
EVP_MD_CTX_destroy(evp_md_ctx_);
evp_md_ctx_ = NULL;
}
if (ecdsa_sig_)
{
ECDSA_SIG_free(ecdsa_sig_);
ecdsa_sig_ = NULL;
}
is_error_ = false;
err_str_.clear();
log_oss_.str("");
}
bool is_error()
{
return is_error_;
}
string err_str()
{
return err_str_;
}
string log_str()
{
return log_oss_.str();
}
private:
bool is_error_;
string err_str_;
ostringstream log_oss_;
EC_KEY* private_key_;
BIO* private_key_bio_;
EVP_MD_CTX* evp_md_ctx_;
ECDSA_SIG* ecdsa_sig_;
string hash(const string& data)
{
evp_md_ctx_ = EVP_MD_CTX_create();
if (0 == EVP_DigestInit(evp_md_ctx_,EVP_sha256()))
{
is_error_ = true;
err_str_.append("EVP_DigestInit failed\n");
return "";
}
if (0 == EVP_DigestUpdate(evp_md_ctx_,data.data(),data.size()))
{
is_error_ = true;
err_str_.append("EVP_DigestUpdate failed\n");
return "";
}
std::string result;
unsigned int len = 0;
result.resize(EVP_MD_CTX_size(evp_md_ctx_));
if (EVP_DigestFinal(evp_md_ctx_,(unsigned char*)result.data(),&len) == 0)
{
is_error_ = true;
err_str_.append("EVP_DigestFinal failed\n");
return "";
}
result.resize(len);
return result;
}
string bn2raw(BIGNUM* bn)
{
string result;
result.resize(BN_num_bytes(bn));
log_oss_ << "\nresult size: " << result.size();
BN_bn2bin(bn,(unsigned char*)result.data());
log_oss_ << "\nresult size: " << result.size();
log_oss_ << "\nresult char: " << result[0];
log_oss_ << "\nresult hex : " << BN_bn2hex(bn);
if (result.size() % 2 == 1 && result[0] == 0x00)
{
return result.substr(1);
}
log_oss_ << "\nresult size: " << result.size();
return result;
}
};
有时签名无效。苹果返回 invalid_client
。我将client_secret粘贴到jwt.io,jwt.io也说无效signaure。当签名有效时,签名的长度是63而不是64。日志信息显示BN_bn2bin的结果大小有时在signature->r或signature-s上是31而不是32。
有人可以就这种情况提供一些建议吗?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。