我对C ++和OpenSSL非常陌生。我必须通过C ++中的OpenSSL使用公钥来验证给定的JWT令牌(算法RS256)。我正在使用以下算法来验证JWT令牌。
// signature algorithm
data = base64urlEncode( header ) + “.” + base64urlEncode( payload )
hashedData = hash( data, secret )
signature = base64urlEncode( hashedData )
我在Mac系统上,正在使用g ++编译我的代码。终端上的openssl version
显示LibreSSL 2.6.5
。
// Assume that base64 encode and decode functions are available
bool RSAVerifySignature( RSA* rsa, std::string token, std::string pub_key) {
std::vector<std::string> tokenParts;
split(token, tokenParts, '.');
std::string decoded_header = tokenParts[0];
std::string header = base64_encode(reinterpret_cast<const unsigned char*>(decoded_header.c_str()),
decoded_header.length());
std::string decoded_body = tokenParts[1];
std::string body = base64_encode(reinterpret_cast<const unsigned char*>(decoded_body.c_str()),
decoded_body.length());
std::string sig = tokenParts[2];
EVP_PKEY* pubKey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(pubKey, rsa);
EVP_MD_CTX* m_RSAVerifyCtx = EVP_MD_CTX_create();
if (1 != EVP_DigestVerifyInit(m_RSAVerifyCtx, NULL, EVP_sha256(), NULL, pubKey)) {
printf("verify init failed....\n");
} else {
printf("verify init passed....\n");
}
if (1 != EVP_DigestVerifyUpdate(m_RSAVerifyCtx, (unsigned char *)header.data(), header.length())) {
printf("DigestVerifyUpdate for header failed....\n");
} else {
printf("DigestVerifyUpdate for header passed....\n");
}
if (1 != EVP_DigestVerifyUpdate(m_RSAVerifyCtx, ".", 1)) {
printf("DigestVerifyUpdate for dot failed\n");
} else {
printf("DigestVerifyUpdate for dot passed\n");
}
if (1 != EVP_DigestVerifyUpdate(m_RSAVerifyCtx, (unsigned char *)body.data(), body.length())) {
printf("DigestVerifyUpdate for body failed\n");
} else {
printf("DigestVerifyUpdate for body passed\n");
}
int result = EVP_DigestVerifyFinal(m_RSAVerifyCtx, (unsigned char *)sig.data(), sig.length());
return result;
}
RSA* createPublicRSA(std::string key) {
RSA *rsa = NULL;
BIO *keybio;
const char* c_string = key.c_str();
keybio = BIO_new_mem_buf((void*)c_string, -1);
if (keybio==NULL) {
return 0;
}
rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa,NULL, NULL);
return rsa;
}
int main()
{
std::string token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.POstGetfAytaZS82wHcjoTyoqhMyxXiWdR7Nn7A29DNSl0EiXLdwJ6xC6AfgZWF1bOsS_TuYI3OG85AmiExREkrS6tDfTQ2B3WXlrr-wp5AokiRbz3_oB4OxG-W9KcEEbDRcZc0nH3L7LzYptiy1PtAylQGxHTWZXtGz4ht0bAecBgmpdgXMguEIcoqPJ1n3pIWk_dUZegpqx0Lka21H6XxUTxiy8OcaarA8zdnPUnV6AmNP3ecFawIFYdvJB_cm-GvpCSbr8G8y_Mllj8f4x9nBH8pQux89_6gUY618iYv7tuPWBFfEbLxtF2pZS6YC1aSfLQxeNe8djT9YjpvRZA";
std::string publicKey = "-----BEGIN PUBLIC KEY-----"\
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnzyis1ZjfNB0bBgKFMSv"\
"vkTtwlvBsaJq7S5wA+kzeVOVpVWwkWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHc"\
"aT92whREFpLv9cj5lTeJSibyr/Mrm/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIy"\
"tvHWTxZYEcXLgAXFuUuaS3uF9gEiNQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0"\
"e+lf4s4OxQawWD79J9/5d3Ry0vbV3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWb"\
"V6L11BWkpzGXSW4Hv43qa+GSYOD2QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9"\
"MwIDAQAB"\
"-----END PUBLIC KEY-----";
RSA* publicRSA = createPublicRSA(publicKey);
bool result = RSAVerifySignature(publicRSA, token, publicKey);
return 0;
}
我在Segmentation fault: 11
的电话中接到EVP_DigestVerifyFinal
。我不知道我在哪里错。请帮忙。
答案 0 :(得分:0)
如果您进行了一些基本的错误检查,您将看到createPublicRSA函数返回一个nullptr。这是因为PEM_read_bio_RSA_PUBKEY期望看到换行符,并且您的publicKey字符串没有任何内容。
如果将其更改为具有换行符,则应该能够创建RSA密钥。
例如
std::string publicKey = "-----BEGIN PUBLIC KEY-----\n"\
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnzyis1ZjfNB0bBgKFMSv\n"\
"vkTtwlvBsaJq7S5wA+kzeVOVpVWwkWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHc\n"\
"aT92whREFpLv9cj5lTeJSibyr/Mrm/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIy\n"\
"tvHWTxZYEcXLgAXFuUuaS3uF9gEiNQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0\n"\
"e+lf4s4OxQawWD79J9/5d3Ry0vbV3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWb\n"\
"V6L11BWkpzGXSW4Hv43qa+GSYOD2QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9\n"\
"MwIDAQAB\n"\
"-----END PUBLIC KEY-----\n";
您的代码也将无法使用,因为您不需要“编码”标题和正文,但是您需要“ base64url解码”签名,因为它必须是二进制值才能生效。
以下代码对我有用:
bool RSAVerifySignature(RSA* rsa, std::string const& token)
{
auto const pub_key_handle = make_handle(EVP_PKEY_new(), EVP_PKEY_free);
if (!pub_key_handle)
{
RSA_free(rsa);
return false;
}
EVP_PKEY_assign_RSA(pub_key_handle.get(), rsa);
std::vector<std::string> token_parts;
split(token, token_parts, '.');
if (token_parts.size() != 3) return false;
auto& decoded_header = token_parts[0];
auto& decoded_body = token_parts[1];
auto sig_decoded = base64_url_decode(token_parts[2]);
auto const rsa_verify_ctx = make_handle(EVP_MD_CTX_create(), EVP_MD_CTX_free);
if (!rsa_verify_ctx) return false;
if (1 != EVP_DigestVerifyInit(rsa_verify_ctx.get(), nullptr, EVP_sha256(), nullptr, pub_key_handle.get())) return false;
if (1 != EVP_DigestVerifyUpdate(rsa_verify_ctx.get(), reinterpret_cast<unsigned char*>(decoded_header.data()), decoded_header.length())) return false;
if (1 != EVP_DigestVerifyUpdate(rsa_verify_ctx.get(), ".", 1)) return false;
if (1 != EVP_DigestVerifyUpdate(rsa_verify_ctx.get(), reinterpret_cast<unsigned char*>(decoded_body.data()), decoded_body.length())) return false;
return 1 == EVP_DigestVerifyFinal(rsa_verify_ctx.get(), reinterpret_cast<unsigned char*>(sig_decoded.data()), sig_decoded.length());
}
答案 1 :(得分:0)
通过CTX清理实现代码的安全性
bool sha_validate( const EVP_MD* type, const std::string& input, const std::vector<unsigned char>& digest )
{
if( !rsa )
return false;
EVP_PKEY* pub_key = EVP_PKEY_new();
EVP_PKEY_assign_RSA(pub_key, rsa);
EVP_MD_CTX* rsa_verify_ctx = EVP_MD_CTX_create();
auto ctx_free = scope_remove( [rsa_verify_ctx]() {
EVP_MD_CTX_cleanup( rsa_verify_ctx );
EVP_MD_CTX_destroy( rsa_verify_ctx );
});
if (EVP_DigestVerifyInit( rsa_verify_ctx,NULL, type, NULL, pub_key ) <=0 )
return false;
if (EVP_DigestVerifyUpdate( rsa_verify_ctx, input.c_str(), input.size() ) <= 0)
return false;
return EVP_DigestVerifyFinal( rsa_verify_ctx, &digest[0], digest.size() ) == 1;
}
bool sha_validate( int type, const std::string& input, const std::vector<unsigned char>& digest )
{
bool result = false;
if( type & RsaOaep::SHA1 )
result = sha_validate( EVP_sha1(), input, digest );
if( !result && ( type & RsaOaep::SHA256 ) == static_cast<int>(RsaOaep::SHA256) )
result = sha_validate( EVP_sha256(), input, digest );
return result;
}
RSA* rsa = nullptr;