1#ifndef CPP_UTILITIES_MISC_VERIFICATION_H
2#define CPP_UTILITIES_MISC_VERIFICATION_H
7#include <openssl/err.h>
8#include <openssl/evp.h>
9#include <openssl/pem.h>
24 const auto errCode = ERR_get_error();
26 return "unknown OpenSSL error";
28 auto buffer = std::array<char, 256>();
29 ERR_error_string_n(errCode, buffer.data(), buffer.size());
30 return std::string(buffer.data());
35inline std::string
extractPemBody(std::string_view pem, std::string_view header)
37 auto body = std::string();
38 auto begin = pem.find(header);
39 if (begin == std::string_view::npos) {
42 begin += header.size();
44 auto end = pem.find(
"-----END", begin);
45 if (end == std::string_view::npos) {
49 body = std::string(pem.data() + begin, end - begin);
50 body.erase(std::remove_if(body.begin(), body.end(), ::isspace), body.end());
56inline std::string
parsePemSignature(std::string_view pemSignature, std::pair<std::unique_ptr<std::uint8_t[]>, std::uint32_t> &decodedSignature)
58 const auto pemSignatureBody =
extractPemBody(pemSignature,
"-----BEGIN SIGNATURE-----");
59 if (pemSignatureBody.empty()) {
60 return "invalid or missing PEM signature block";
63 decodedSignature =
decodeBase64(pemSignatureBody.data(),
static_cast<std::uint32_t
>(pemSignatureBody.size()));
66 return "unable to decode PEM signature block";
107inline std::string
verifySignature(std::string_view publicKeyPem, std::string_view signaturePem, std::string_view data)
109 auto error = std::string();
110 auto derSignature = std::pair<std::unique_ptr<std::uint8_t[]>, std::uint32_t>();
115 BIO *
const keyBio = BIO_new_mem_buf(publicKeyPem.data(),
static_cast<int>(publicKeyPem.size()));
120 EVP_PKEY *
const publicKey = PEM_read_bio_PUBKEY(keyBio,
nullptr,
nullptr,
nullptr);
126 EVP_MD_CTX *
const mdCtx = EVP_MD_CTX_new();
128 EVP_PKEY_free(publicKey);
132 if (EVP_DigestVerifyInit(mdCtx,
nullptr, EVP_sha256(),
nullptr, publicKey) != 1) {
134 }
else if (EVP_DigestVerifyUpdate(mdCtx, data.data(), data.size()) != 1) {
137 switch (EVP_DigestVerifyFinal(mdCtx, derSignature.first.get(), derSignature.second)) {
139 error =
"incorrect signature";
149 EVP_MD_CTX_free(mdCtx);
150 EVP_PKEY_free(publicKey);
162template <
class Keys,
class VerifyFunction = MainVerifyFunctionType>
163inline std::string
verifySignature(Keys &&publicKeysPem, std::string_view signaturePem, std::string_view data,
166 auto error = std::string(
"no keys provided");
167 for (
const auto publicKeyPem : publicKeysPem) {
168 if ((error = verifyFunction(publicKeyPem, signaturePem, data)).empty()) {
The ConversionException class is thrown by the various conversion functions of this library when a co...
std::string extractPemBody(std::string_view pem, std::string_view header)
Extracts the base64-encoded body from a PEM block.
std::string parsePemSignature(std::string_view pemSignature, std::pair< std::unique_ptr< std::uint8_t[]>, std::uint32_t > &decodedSignature)
Converts PEM-encoded signature into DER-encoded signature.
std::string getOpenSslError()
Returns the current OpenSSL error.
Contains all utilities provides by the c++utilities library.
std::string(*)(std::string_view, std::string_view, std::string_view) MainVerifyFunctionType
The signature of the main verifySignature() function.
std::string verifySignature(std::string_view publicKeyPem, std::string_view signaturePem, std::string_view data)
Verifies data with the specified public key publicKeyPem and signature signaturePem.
CPP_UTILITIES_EXPORT std::pair< std::unique_ptr< std::uint8_t[]>, std::uint32_t > decodeBase64(const char *encodedStr, const std::uint32_t strSize)
Decodes the specified Base64 encoded string.