/* 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); }