diff options
Diffstat (limited to 'libtransport/src/auth/verifier.cc')
-rw-r--r-- | libtransport/src/auth/verifier.cc | 427 |
1 files changed, 239 insertions, 188 deletions
diff --git a/libtransport/src/auth/verifier.cc b/libtransport/src/auth/verifier.cc index c6648a763..c9ac1650f 100644 --- a/libtransport/src/auth/verifier.cc +++ b/libtransport/src/auth/verifier.cc @@ -16,168 +16,125 @@ #include <hicn/transport/auth/verifier.h> #include <protocols/errors.h> -extern "C" { -#ifndef _WIN32 -TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat") -#endif -#include <hicn/hicn.h> -} - -#include <sys/stat.h> - using namespace std; namespace transport { namespace auth { -const std::vector<VerificationPolicy> Verifier::DEFAULT_FAILED_POLICIES = { +const vector<VerificationPolicy> Verifier::DEFAULT_FAILED_POLICIES = { VerificationPolicy::DROP, VerificationPolicy::ABORT, }; +// --------------------------------------------------------- +// Base Verifier +// --------------------------------------------------------- Verifier::Verifier() - : hasher_(nullptr), - verifier_(nullptr), - verification_failed_cb_(interface::VOID_HANDLER), - failed_policies_(DEFAULT_FAILED_POLICIES) { - parcSecurity_Init(); - PARCInMemoryVerifier *in_memory_verifier = parcInMemoryVerifier_Create(); - verifier_ = - parcVerifier_Create(in_memory_verifier, PARCInMemoryVerifierAsVerifier); - parcInMemoryVerifier_Release(&in_memory_verifier); -} + : verification_failed_cb_(interface::VOID_HANDLER), + failed_policies_(DEFAULT_FAILED_POLICIES) {} -Verifier::~Verifier() { - if (hasher_) parcCryptoHasher_Release(&hasher_); - if (verifier_) parcVerifier_Release(&verifier_); - parcSecurity_Fini(); -} +Verifier::~Verifier() {} bool Verifier::verifyPacket(PacketPtr packet) { - bool valid_packet = false; core::Packet::Format format = packet->getFormat(); if (!packet->authenticationHeader()) { throw errors::MalformedAHPacketException(); } - // Get crypto suite and hash type - auto suite = static_cast<PARCCryptoSuite>(packet->getValidationAlgorithm()); - PARCCryptoHashType hash_type = parcCryptoSuite_GetCryptoHash(suite); + // Get crypto suite, hash type, signature length + CryptoSuite suite = packet->getValidationAlgorithm(); + CryptoHashType hash_type = getHashType(suite); + size_t signature_len = packet->getSignatureSizeReal(); // Copy IP+TCP / ICMP header before zeroing them hicn_header_t header_copy; hicn_packet_copy_header(format, packet->packet_start_, &header_copy, false); + packet->setSignatureSizeGap(0u); - // Fetch packet signature + // Retrieve packet signature uint8_t *packet_signature = packet->getSignature(); - size_t signature_len = Verifier::getSignatureSize(packet); vector<uint8_t> signature_raw(packet_signature, packet_signature + signature_len); - // Create a signature buffer from the raw packet signature - PARCBuffer *bits = - parcBuffer_Wrap(signature_raw.data(), signature_len, 0, signature_len); - parcBuffer_Rewind(bits); - - // If the signature algo is ECDSA, the signature might be shorter than the - // signature field - PARCSigningAlgorithm algo = parcCryptoSuite_GetSigningAlgorithm(suite); - if (algo == PARCSigningAlgorithm_ECDSA) { - while (parcBuffer_HasRemaining(bits) && parcBuffer_GetUint8(bits) == 0) - ; - parcBuffer_SetPosition(bits, parcBuffer_Position(bits) - 1); - } - - if (!parcBuffer_HasRemaining(bits)) { - parcBuffer_Release(&bits); - return false; - } - - // Create a signature object from the signature buffer - PARCSignature *signature = parcSignature_Create( - parcCryptoSuite_GetSigningAlgorithm(suite), hash_type, bits); - - // Fetch the key to verify the signature - KeyId key_buffer = packet->getKeyId(); - PARCBuffer *buffer = parcBuffer_Wrap(key_buffer.first, key_buffer.second, 0, - key_buffer.second); - PARCKeyId *key_id = parcKeyId_Create(buffer); - // Reset fields that are not used to compute signature packet->resetForHash(); - // Compute the packet hash - if (!hasher_) - setHasher(parcVerifier_GetCryptoHasher(verifier_, key_id, hash_type)); - CryptoHash local_hash = computeHash(packet); - - // Compare the packet signature to the locally computed one - valid_packet = parcVerifier_VerifyDigestSignature( - verifier_, key_id, local_hash.hash_, suite, signature); + // Check signatures + bool valid_packet = verifyBuffer(static_cast<utils::MemBuf *>(packet), + signature_raw, hash_type); - // Restore the fields that were reset + // Restore header hicn_packet_copy_header(format, &header_copy, packet->packet_start_, false); - - // Release allocated objects - parcBuffer_Release(&buffer); - parcKeyId_Release(&key_id); - parcSignature_Release(&signature); - parcBuffer_Release(&bits); + packet->setSignatureSizeGap(packet->getSignatureSize() - signature_len); return valid_packet; } -vector<VerificationPolicy> Verifier::verifyPackets( - const vector<PacketPtr> &packets) { - vector<VerificationPolicy> policies(packets.size(), VerificationPolicy::DROP); +Verifier::PolicyMap Verifier::verifyPackets(const vector<PacketPtr> &packets) { + PolicyMap policies; + + for (const auto &packet : packets) { + Suffix suffix = packet->getName().getSuffix(); + VerificationPolicy policy = VerificationPolicy::ABORT; - for (unsigned int i = 0; i < packets.size(); ++i) { - if (verifyPacket(packets[i])) { - policies[i] = VerificationPolicy::ACCEPT; + if (verifyPacket(packet)) { + policy = VerificationPolicy::ACCEPT; } - callVerificationFailedCallback(packets[i], policies[i]); + policies[suffix] = policy; + callVerificationFailedCallback(packet, policy); } return policies; } -vector<VerificationPolicy> Verifier::verifyPackets( - const vector<PacketPtr> &packets, - const unordered_map<Suffix, HashEntry> &suffix_map) { - vector<VerificationPolicy> policies(packets.size(), - VerificationPolicy::UNKNOWN); +Verifier::PolicyMap Verifier::verifyHashes(const SuffixMap &packet_map, + const SuffixMap &suffix_map) { + PolicyMap policies; - for (unsigned int i = 0; i < packets.size(); ++i) { - uint32_t suffix = packets[i]->getName().getSuffix(); - auto manifest_hash = suffix_map.find(suffix); + for (const auto &packet_hash : packet_map) { + VerificationPolicy policy = VerificationPolicy::UNKNOWN; + auto manifest_hash = suffix_map.find(packet_hash.first); if (manifest_hash != suffix_map.end()) { - CryptoHashType hash_type = manifest_hash->second.first; - CryptoHash packet_hash = packets[i]->computeDigest(hash_type); - - if (!CryptoHash::compareBinaryDigest( - packet_hash.getDigest<uint8_t>().data(), - manifest_hash->second.second.data(), hash_type)) { - policies[i] = VerificationPolicy::ABORT; - } else { - policies[i] = VerificationPolicy::ACCEPT; + policy = VerificationPolicy::ABORT; + + if (packet_hash.second == manifest_hash->second) { + policy = VerificationPolicy::ACCEPT; } } - callVerificationFailedCallback(packets[i], policies[i]); + policies[packet_hash.first] = policy; } return policies; } -void Verifier::addKey(PARCKey *key) { parcVerifier_AddKey(verifier_, key); } +Verifier::PolicyMap Verifier::verifyPackets(const vector<PacketPtr> &packets, + const SuffixMap &suffix_map) { + PolicyMap policies; + + for (const auto &packet : packets) { + Suffix suffix = packet->getName().getSuffix(); + VerificationPolicy policy = VerificationPolicy::UNKNOWN; + auto manifest_hash = suffix_map.find(suffix); + + if (manifest_hash != suffix_map.end()) { + policy = VerificationPolicy::ABORT; + CryptoHashType hash_type = manifest_hash->second.getType(); + CryptoHash packet_hash = packet->computeDigest(hash_type); + + if (packet_hash == manifest_hash->second) { + policy = VerificationPolicy::ACCEPT; + } + } -void Verifier::setHasher(PARCCryptoHasher *hasher) { - parcAssertNotNull(hasher, "Expected non-null hasher"); - if (hasher_) parcCryptoHasher_Release(&hasher_); - hasher_ = parcCryptoHasher_Acquire(hasher); + policies[suffix] = policy; + callVerificationFailedCallback(packet, policy); + } + + return policies; } void Verifier::setVerificationFailedCallback( @@ -192,27 +149,6 @@ void Verifier::getVerificationFailedCallback( *verfication_failed_cb = &verification_failed_cb_; } -size_t Verifier::getSignatureSize(const PacketPtr packet) { - return packet->getSignatureSize(); -} - -CryptoHash Verifier::computeHash(PacketPtr packet) { - parcAssertNotNull(hasher_, "Expected non-null hasher"); - - CryptoHasher crypto_hasher(hasher_); - const utils::MemBuf &header_chain = *packet; - const utils::MemBuf *current = &header_chain; - - crypto_hasher.init(); - - do { - crypto_hasher.updateBytes(current->data(), current->length()); - current = current->next(); - } while (current != &header_chain); - - return crypto_hasher.finalize(); -} - void Verifier::callVerificationFailedCallback(PacketPtr packet, VerificationPolicy &policy) { if (verification_failed_cb_ == interface::VOID_HANDLER) { @@ -228,107 +164,222 @@ void Verifier::callVerificationFailedCallback(PacketPtr packet, } } +// --------------------------------------------------------- +// Void Verifier +// --------------------------------------------------------- bool VoidVerifier::verifyPacket(PacketPtr packet) { return true; } -vector<VerificationPolicy> VoidVerifier::verifyPackets( +bool VoidVerifier::verifyBuffer(const vector<uint8_t> &buffer, + const vector<uint8_t> &signature, + CryptoHashType hash_type) { + return true; +} + +bool VoidVerifier::verifyBuffer(const utils::MemBuf *buffer, + const vector<uint8_t> &signature, + CryptoHashType hash_type) { + return true; +} + +Verifier::PolicyMap VoidVerifier::verifyPackets( const vector<PacketPtr> &packets) { - return vector<VerificationPolicy>(packets.size(), VerificationPolicy::ACCEPT); + PolicyMap policies; + + for (const auto &packet : packets) { + policies[packet->getName().getSuffix()] = VerificationPolicy::ACCEPT; + } + + return policies; } -vector<VerificationPolicy> VoidVerifier::verifyPackets( - const vector<PacketPtr> &packets, - const unordered_map<Suffix, HashEntry> &suffix_map) { - return vector<VerificationPolicy>(packets.size(), VerificationPolicy::ACCEPT); +Verifier::PolicyMap VoidVerifier::verifyPackets( + const vector<PacketPtr> &packets, const SuffixMap &suffix_map) { + return verifyPackets(packets); } -AsymmetricVerifier::AsymmetricVerifier(PARCKey *pub_key) { addKey(pub_key); } +// --------------------------------------------------------- +// Asymmetric Verifier +// --------------------------------------------------------- +AsymmetricVerifier::AsymmetricVerifier(shared_ptr<EVP_PKEY> key) { + setKey(key); +} AsymmetricVerifier::AsymmetricVerifier(const string &cert_path) { - setCertificate(cert_path); + useCertificate(cert_path); +} + +AsymmetricVerifier::AsymmetricVerifier(shared_ptr<X509> cert) { + useCertificate(cert); } -void AsymmetricVerifier::setCertificate(const string &cert_path) { - PARCCertificateFactory *factory = parcCertificateFactory_Create( - PARCCertificateType_X509, PARCContainerEncoding_PEM); +void AsymmetricVerifier::setKey(shared_ptr<EVP_PKEY> key) { key_ = key; }; - struct stat buffer; - if (stat(cert_path.c_str(), &buffer) != 0) { - throw errors::RuntimeException("Certificate does not exist"); +void AsymmetricVerifier::useCertificate(const string &cert_path) { + FILE *certf = fopen(cert_path.c_str(), "rb"); + + if (certf == nullptr) { + throw errors::RuntimeException("Certificate not found"); } - PARCCertificate *certificate = - parcCertificateFactory_CreateCertificateFromFile(factory, - cert_path.c_str(), NULL); - PARCKey *key = parcCertificate_GetPublicKey(certificate); + shared_ptr<X509> cert = shared_ptr<X509>( + PEM_read_X509(certf, nullptr, nullptr, nullptr), ::X509_free); + useCertificate(cert); - addKey(key); + fclose(certf); +} - parcKey_Release(&key); - parcCertificateFactory_Release(&factory); +void AsymmetricVerifier::useCertificate(shared_ptr<X509> cert) { + key_ = shared_ptr<EVP_PKEY>(X509_get_pubkey(cert.get()), ::EVP_PKEY_free); } -SymmetricVerifier::SymmetricVerifier(const string &passphrase) - : passphrase_(nullptr), signer_(nullptr) { - setPassphrase(passphrase); +bool AsymmetricVerifier::verifyBuffer(const vector<uint8_t> &buffer, + const vector<uint8_t> &signature, + CryptoHashType hash_type) { + CryptoHashEVP hash_evp = CryptoHash::getEVP(hash_type); + + if (hash_evp == nullptr) { + throw errors::RuntimeException("Unknown hash type"); + } + + shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free); + + if (mdctx == nullptr) { + throw errors::RuntimeException("Digest context allocation failed"); + } + + if (EVP_DigestVerifyInit(mdctx.get(), nullptr, (*hash_evp)(), nullptr, + key_.get()) != 1) { + throw errors::RuntimeException("Digest initialization failed"); + } + + if (EVP_DigestVerifyUpdate(mdctx.get(), buffer.data(), buffer.size()) != 1) { + throw errors::RuntimeException("Digest update failed"); + } + + return EVP_DigestVerifyFinal(mdctx.get(), signature.data(), + signature.size()) == 1; +} + +bool AsymmetricVerifier::verifyBuffer(const utils::MemBuf *buffer, + const vector<uint8_t> &signature, + CryptoHashType hash_type) { + CryptoHashEVP hash_evp = CryptoHash::getEVP(hash_type); + + if (hash_evp == nullptr) { + throw errors::RuntimeException("Unknown hash type"); + } + + const utils::MemBuf *p = buffer; + shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free); + + if (mdctx == nullptr) { + throw errors::RuntimeException("Digest context allocation failed"); + } + + if (EVP_DigestVerifyInit(mdctx.get(), nullptr, (*hash_evp)(), nullptr, + key_.get()) != 1) { + throw errors::RuntimeException("Digest initialization failed"); + } + + do { + if (EVP_DigestVerifyUpdate(mdctx.get(), p->data(), p->length()) != 1) { + throw errors::RuntimeException("Digest update failed"); + } + + p = p->next(); + } while (p != buffer); + + return EVP_DigestVerifyFinal(mdctx.get(), signature.data(), + signature.size()) == 1; } -SymmetricVerifier::~SymmetricVerifier() { - if (passphrase_) parcBuffer_Release(&passphrase_); - if (signer_) parcSigner_Release(&signer_); +// --------------------------------------------------------- +// Symmetric Verifier +// --------------------------------------------------------- +SymmetricVerifier::SymmetricVerifier(const string &passphrase) { + setPassphrase(passphrase); } +// Create and set a symmetric key from a passphrase. void SymmetricVerifier::setPassphrase(const string &passphrase) { - if (passphrase_) parcBuffer_Release(&passphrase_); - - PARCBufferComposer *composer = parcBufferComposer_Create(); - parcBufferComposer_PutString(composer, passphrase.c_str()); - passphrase_ = parcBufferComposer_ProduceBuffer(composer); - parcBufferComposer_Release(&composer); + key_ = shared_ptr<EVP_PKEY>( + EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, nullptr, + (const unsigned char *)passphrase.c_str(), + passphrase.size()), + EVP_PKEY_free); } -void SymmetricVerifier::setSigner(const PARCCryptoSuite &suite) { - parcAssertNotNull(passphrase_, "Expected non-null passphrase"); +bool SymmetricVerifier::verifyBuffer(const vector<uint8_t> &buffer, + const vector<uint8_t> &signature, + CryptoHashType hash_type) { + CryptoHashEVP hash_evp = CryptoHash::getEVP(hash_type); - if (signer_) parcSigner_Release(&signer_); + if (hash_evp == nullptr) { + throw errors::RuntimeException("Unknown hash type"); + } + + vector<uint8_t> signature_bis(signature.size()); + size_t signature_bis_len; + shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free); - PARCSymmetricKeyStore *key_store = parcSymmetricKeyStore_Create(passphrase_); - PARCSymmetricKeySigner *key_signer = parcSymmetricKeySigner_Create( - key_store, parcCryptoSuite_GetCryptoHash(suite)); - signer_ = parcSigner_Create(key_signer, PARCSymmetricKeySignerAsSigner); + if (mdctx == nullptr) { + throw errors::RuntimeException("Digest context allocation failed"); + } - PARCKeyId *key_id = parcSigner_CreateKeyId(signer_); - PARCKey *key = parcKey_CreateFromSymmetricKey( - key_id, parcSigner_GetSigningAlgorithm(signer_), passphrase_); + if (EVP_DigestSignInit(mdctx.get(), nullptr, (*hash_evp)(), nullptr, + key_.get()) != 1) { + throw errors::RuntimeException("Digest initialization failed"); + } - addKey(key); - setHasher(parcSigner_GetCryptoHasher(signer_)); + if (EVP_DigestSignUpdate(mdctx.get(), buffer.data(), buffer.size()) != 1) { + throw errors::RuntimeException("Digest update failed"); + } - parcSymmetricKeyStore_Release(&key_store); - parcSymmetricKeySigner_Release(&key_signer); - parcKeyId_Release(&key_id); - parcKey_Release(&key); + if (EVP_DigestSignFinal(mdctx.get(), signature_bis.data(), + &signature_bis_len) != 1) { + throw errors::RuntimeException("Digest computation failed"); + } + + return signature == signature_bis && signature.size() == signature_bis_len; } -vector<VerificationPolicy> SymmetricVerifier::verifyPackets( - const vector<PacketPtr> &packets) { - vector<VerificationPolicy> policies(packets.size(), VerificationPolicy::DROP); +bool SymmetricVerifier::verifyBuffer(const utils::MemBuf *buffer, + const vector<uint8_t> &signature, + CryptoHashType hash_type) { + CryptoHashEVP hash_evp = CryptoHash::getEVP(hash_type); + + if (hash_evp == nullptr) { + throw errors::RuntimeException("Unknown hash type"); + } - for (unsigned int i = 0; i < packets.size(); ++i) { - auto suite = - static_cast<PARCCryptoSuite>(packets[i]->getValidationAlgorithm()); + const utils::MemBuf *p = buffer; + vector<uint8_t> signature_bis(signature.size()); + size_t signature_bis_len; + shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free); - if (!signer_ || suite != parcSigner_GetCryptoSuite(signer_)) { - setSigner(suite); - } + if (mdctx == nullptr) { + throw errors::RuntimeException("Digest context allocation failed"); + } - if (verifyPacket(packets[i])) { - policies[i] = VerificationPolicy::ACCEPT; + if (EVP_DigestSignInit(mdctx.get(), nullptr, (*hash_evp)(), nullptr, + key_.get()) != 1) { + throw errors::RuntimeException("Digest initialization failed"); + } + + do { + if (EVP_DigestSignUpdate(mdctx.get(), p->data(), p->length()) != 1) { + throw errors::RuntimeException("Digest update failed"); } - callVerificationFailedCallback(packets[i], policies[i]); + p = p->next(); + } while (p != buffer); + + if (EVP_DigestSignFinal(mdctx.get(), signature_bis.data(), + &signature_bis_len) != 1) { + throw errors::RuntimeException("Digest computation failed"); } - return policies; + return signature == signature_bis && signature.size() == signature_bis_len; } } // namespace auth |