/*
This file is part of Bolixo.
Bolixo is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bolixo is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bolixo. If not, see .
*/
/*
Various functions to verify signature
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
namespace {
struct BIOFreeAll { void operator()(BIO* p) { BIO_free_all(p); } };
}
// Assumes no newlines or extra characters in encoded string
static std::vector Base64Decode(const char* encoded)
{
std::unique_ptr b64(BIO_new(BIO_f_base64()));
BIO_set_flags(b64.get(), BIO_FLAGS_BASE64_NO_NL);
BIO* source = BIO_new_mem_buf(encoded, -1); // read-only source
BIO_push(b64.get(), source);
const int maxlen = strlen(encoded) / 4 * 3 + 1;
std::vector decoded(maxlen);
const int len = BIO_read(b64.get(), decoded.data(), maxlen);
decoded.resize(len);
return decoded;
}
int fs_verify(
const BOB_TYPE &msg,
EVP_PKEY *key,
PARAM_STRING sig64)
{
int ret = -1;
int len=strlen(sig64.ptr);
if (len < 2000){
/* Initialize `key` with a public key */
char sig64_clean[len+1];
char *dst = sig64_clean;
const char *pt = sig64.ptr;
while (*pt != '\0'){
char car = *pt++;
if (car > ' ') *dst++ = car;
}
*dst = '\0';
vector sig = Base64Decode(sig64_clean);
EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
if (mdctx != NULL){
if(EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, key) == 1){
// Initialize `key` with a public key
if(EVP_DigestVerifyUpdate(mdctx, msg.getbuffer(),msg.getsize()) == 1){
if(EVP_DigestVerifyFinal(mdctx, sig.data(), sig.size()) == 1){
// Success
ret = 0;
}else{
// Failure
}
}
}
EVP_MD_CTX_destroy(mdctx);
}
}
return ret;
}
int fs_verify(
PARAM_STRING msg,
EVP_PKEY *key,
PARAM_STRING sig64)
{
return fs_verify(BOB_TYPE(msg.ptr,strlen(msg.ptr),false),key,sig64);
}
EVP_PKEY *fs_load_public (PARAM_STRING p)
{
BIO *bio = BIO_new_mem_buf((void*)p.ptr, strlen(p.ptr));
EVP_PKEY *pkey = PEM_read_bio_PUBKEY(bio, NULL,NULL,NULL);
BIO_free_all (bio);
return pkey;
}
void fs_free_public (EVP_PKEY *p)
{
EVP_PKEY_free (p);
}
// Validate a public key
int fs_valid_pubkey(const char *pubkey)
{
int ret = -1;
static const char *pub_begin = "-----BEGIN PUBLIC KEY-----\n";
static unsigned pub_begin_len = strlen(pub_begin);
static const char *pub_end = "-----END PUBLIC KEY-----\n";
if (strncmp(pubkey,pub_begin,pub_begin_len)==0){
const char *pt = pubkey + pub_begin_len;
while (*pt != '\0'){
if (!isalpha(*pt) && !isdigit(*pt) && *pt != '+' && *pt != '/' && *pt != '\n') break;
pt++;
}
if (strcmp(pt,pub_end) == 0) ret = 0;
}
return ret;
}
int fs_verify (PARAM_STRING pubkey, const BOB_TYPE &content, PARAM_STRING signature)
{
int ret = -1;
EVP_PKEY *p = fs_load_public (pubkey);
if (p != NULL){
ret = fs_verify(content,p,signature);
fs_free_public (p);
}
return ret;
}
int fs_verify (PARAM_STRING pubkey, PARAM_STRING content, PARAM_STRING signature)
{
return fs_verify (pubkey,BOB_TYPE(content.ptr,strlen(content.ptr),false),signature);
}