问题描述
我使用 openssl 为 Apple 令牌端点生成 client_secret(JWT)。我发现帖子 https://developer.apple.com/forums/thread/123723 说我们应该解析 R、S 值并连接这两个值。
#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 (将#修改为@)