1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-26 08:14:38 +01:00

Finish OpenSSL RSA implementation

This commit is contained in:
Ted John
2018-05-25 23:12:44 +01:00
parent fe7e8a17de
commit 9e214258c3
4 changed files with 142 additions and 16 deletions

View File

@@ -18,6 +18,7 @@
#define __USE_CNG__
#endif
#undef __USE_CNG__
#ifndef __USE_CNG__
#include "Crypt.h"
@@ -25,6 +26,7 @@
#include <string>
#include <vector>
#include <openssl/evp.h>
#include <openssl/pem.h>
static void OpenSSLThrowOnBadStatus(const std::string_view& name, int status)
{
@@ -109,12 +111,100 @@ public:
class OpenSSLRsaKey final : public RsaKey
{
public:
EVP_PKEY * const EvpKey{};
EVP_PKEY * GetEvpKey() const { return _evpKey; }
void SetPrivate(const std::string_view& pem) override { }
void SetPublic(const std::string_view& pem) override { }
std::string GetPrivate() override { return ""; }
std::string GetPublic() override { return ""; }
void SetPrivate(const std::string_view& pem) override
{
SetKey(pem, true);
}
void SetPublic(const std::string_view& pem) override
{
SetKey(pem, false);
}
std::string GetPrivate() override { return GetKey(true); }
std::string GetPublic() override { return GetKey(false); }
private:
EVP_PKEY * _evpKey{};
void SetKey(const std::string_view& pem, bool isPrivate)
{
// Read PEM data via BIO buffer
auto bio = BIO_new_mem_buf(pem.data(), (int)pem.size());
if (bio == nullptr)
{
throw std::runtime_error("BIO_new_mem_buf failed");
}
auto rsa = isPrivate ?
PEM_read_bio_RSAPrivateKey(bio, nullptr, nullptr, nullptr) :
PEM_read_bio_RSAPublicKey(bio, nullptr, nullptr, nullptr);
if (rsa == nullptr)
{
BIO_free_all(bio);
auto msg = isPrivate ?
"PEM_read_bio_RSAPrivateKey failed" :
"PEM_read_bio_RSAPublicKey failed";
throw std::runtime_error(msg);
}
BIO_free_all(bio);
if (isPrivate && !RSA_check_key(rsa))
{
RSA_free(rsa);
throw std::runtime_error("PEM key was invalid");
}
// Assign new key
EVP_PKEY_free(_evpKey);
_evpKey = EVP_PKEY_new();
EVP_PKEY_set1_RSA(_evpKey, rsa);
RSA_free(rsa);
}
std::string GetKey(bool isPrivate)
{
if (_evpKey == nullptr)
{
throw std::runtime_error("No key has been assigned");
}
auto rsa = EVP_PKEY_get1_RSA(_evpKey);
if (rsa == nullptr)
{
throw std::runtime_error("EVP_PKEY_get1_RSA failed");
}
if (!RSA_check_key(rsa))
{
RSA_free(rsa);
throw std::runtime_error("Loaded RSA key is invalid");
}
auto bio = BIO_new(BIO_s_mem());
if (bio == nullptr)
{
throw std::runtime_error("BIO_new failed");
}
auto status = isPrivate ?
PEM_write_bio_RSAPrivateKey(bio, rsa, nullptr, nullptr, 0, nullptr, nullptr) :
PEM_write_bio_RSAPublicKey(bio, rsa);
if (status != 1)
{
BIO_free_all(bio);
RSA_free(rsa);
throw std::runtime_error("PEM_write_bio_RSAPrivateKey failed");
}
RSA_free(rsa);
auto keylen = BIO_pending(bio);
std::string result(keylen, 0);
BIO_read(bio, result.data(), keylen);
BIO_free_all(bio);
return result;
}
};
class OpenSSLRsaAlgorithm final : public RsaAlgorithm
@@ -122,7 +212,7 @@ class OpenSSLRsaAlgorithm final : public RsaAlgorithm
public:
std::vector<uint8_t> SignData(const RsaKey& key, const void * data, size_t dataLen) override
{
auto evpKey = static_cast<const OpenSSLRsaKey&>(key).EvpKey;
auto evpKey = static_cast<const OpenSSLRsaKey&>(key).GetEvpKey();
EVP_MD_CTX * mdctx{};
try
{
@@ -160,7 +250,7 @@ public:
bool VerifyData(const RsaKey& key, const void * data, size_t dataLen, const void * sig, size_t sigLen) override
{
auto evpKey = static_cast<const OpenSSLRsaKey&>(key).EvpKey;
auto evpKey = static_cast<const OpenSSLRsaKey&>(key).GetEvpKey();
EVP_MD_CTX * mdctx{};
try
{
@@ -182,7 +272,7 @@ public:
OpenSSLThrowOnBadStatus("EVP_DigestVerifyUpdate", status);
}
EVP_MD_CTX_destroy(mdctx);
return status == 0;
return status == 1;
}
catch (const std::exception&)
{