aboutsummaryrefslogtreecommitdiffstats
path: root/libtransport/src/auth/verifier.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libtransport/src/auth/verifier.cc')
-rw-r--r--libtransport/src/auth/verifier.cc370
1 files changed, 370 insertions, 0 deletions
diff --git a/libtransport/src/auth/verifier.cc b/libtransport/src/auth/verifier.cc
new file mode 100644
index 000000000..0919aec7d
--- /dev/null
+++ b/libtransport/src/auth/verifier.cc
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2021-2022 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <hicn/transport/auth/verifier.h>
+#include <hicn/transport/core/global_object_pool.h>
+#include <hicn/transport/core/interest.h>
+#include <protocols/errors.h>
+
+#include "glog/logging.h"
+
+namespace transport {
+namespace auth {
+
+const std::vector<VerificationPolicy> Verifier::DEFAULT_FAILED_POLICIES = {
+ VerificationPolicy::DROP,
+ VerificationPolicy::ABORT,
+};
+
+// ---------------------------------------------------------
+// Base Verifier
+// ---------------------------------------------------------
+Verifier::Verifier()
+ : verification_failed_cb_(interface::VOID_HANDLER),
+ failed_policies_(DEFAULT_FAILED_POLICIES) {}
+
+Verifier::~Verifier() {}
+
+bool Verifier::verifyPacket(PacketPtr packet) {
+ if (!packet->hasAH()) {
+ throw errors::MalformedAHPacketException();
+ }
+
+ // Get crypto suite
+ CryptoSuite suite = packet->getValidationAlgorithm();
+
+ // Copy IP+TCP / ICMP header before zeroing them
+ u8 header_copy[HICN_HDRLEN_MAX];
+ size_t header_len;
+ packet->saveHeader(header_copy, &header_len);
+
+ // Copy bitmap from interest manifest
+ uint32_t request_bitmap[BITMAP_SIZE] = {0};
+ if (packet->isInterest()) {
+ core::Interest *interest = dynamic_cast<core::Interest *>(packet);
+ memcpy(request_bitmap, interest->getRequestBitmap(),
+ BITMAP_SIZE * sizeof(uint32_t));
+ }
+
+ // Retrieve packet signature
+ utils::MemBuf::Ptr signature_raw = packet->getSignature();
+ std::size_t signature_len = packet->getSignatureSize();
+ DCHECK(signature_len <= signature_raw->tailroom());
+ signature_raw->setLength(signature_len);
+
+ // Reset fields that are not used to compute signature
+ packet->resetForHash();
+
+ // Check signatures
+ bool valid_packet =
+ verifyBuffer(static_cast<utils::MemBuf *>(packet), signature_raw, suite);
+
+ // Restore header
+ packet->loadHeader(header_copy, header_len);
+ packet->setSignature(signature_raw);
+ packet->setSignatureSize(signature_raw->length());
+
+ // Restore bitmap in interest manifest
+ if (packet->isInterest()) {
+ core::Interest *interest = dynamic_cast<core::Interest *>(packet);
+ interest->setRequestBitmap(request_bitmap);
+ }
+
+ return valid_packet;
+}
+
+Verifier::PolicyMap Verifier::verifyPackets(
+ const std::vector<PacketPtr> &packets) {
+ PolicyMap policies;
+
+ for (const auto &packet : packets) {
+ Suffix suffix = packet->getName().getSuffix();
+ VerificationPolicy policy = VerificationPolicy::ABORT;
+
+ if (verifyPacket(packet)) {
+ policy = VerificationPolicy::ACCEPT;
+ }
+
+ callVerificationFailedCallback(suffix, policy);
+ policies[suffix] = policy;
+ }
+
+ return policies;
+}
+
+Verifier::PolicyMap Verifier::verifyHashes(const SuffixMap &packet_map,
+ const SuffixMap &suffix_map) {
+ PolicyMap policies;
+
+ 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()) {
+ policy = VerificationPolicy::ABORT;
+
+ if (packet_hash.second == manifest_hash->second) {
+ policy = VerificationPolicy::ACCEPT;
+ }
+ }
+
+ callVerificationFailedCallback(packet_hash.first, policy);
+ policies[packet_hash.first] = policy;
+ }
+
+ return policies;
+}
+
+Verifier::PolicyMap Verifier::verifyPackets(
+ const std::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;
+ }
+ }
+
+ callVerificationFailedCallback(suffix, policy);
+ policies[suffix] = policy;
+ }
+
+ return policies;
+}
+
+void Verifier::setVerificationFailedCallback(
+ VerificationFailedCallback verfication_failed_cb,
+ const std::vector<VerificationPolicy> &failed_policies) {
+ verification_failed_cb_ = verfication_failed_cb;
+ failed_policies_ = failed_policies;
+}
+
+void Verifier::getVerificationFailedCallback(
+ VerificationFailedCallback **verfication_failed_cb) {
+ *verfication_failed_cb = &verification_failed_cb_;
+}
+
+void Verifier::callVerificationFailedCallback(Suffix suffix,
+ VerificationPolicy &policy) {
+ if (verification_failed_cb_ == interface::VOID_HANDLER) {
+ return;
+ }
+
+ if (find(failed_policies_.begin(), failed_policies_.end(), policy) !=
+ failed_policies_.end()) {
+ policy = verification_failed_cb_(suffix, policy);
+ }
+}
+
+// ---------------------------------------------------------
+// Void Verifier
+// ---------------------------------------------------------
+bool VoidVerifier::verifyPacket(PacketPtr packet) { return true; }
+
+bool VoidVerifier::verifyBuffer(const uint8_t *buffer, std::size_t len,
+ const utils::MemBuf::Ptr &signature,
+ CryptoSuite suite) {
+ return true;
+}
+
+bool VoidVerifier::verifyBuffer(const std::vector<uint8_t> &buffer,
+ const utils::MemBuf::Ptr &signature,
+ CryptoSuite suite) {
+ return true;
+}
+
+bool VoidVerifier::verifyBuffer(const utils::MemBuf *buffer,
+ const utils::MemBuf::Ptr &signature,
+ CryptoSuite suite) {
+ return true;
+}
+
+Verifier::PolicyMap VoidVerifier::verifyPackets(
+ const std::vector<PacketPtr> &packets) {
+ PolicyMap policies;
+
+ for (const auto &packet : packets) {
+ auth::Suffix suffix = packet->getName().getSuffix();
+ VerificationPolicy policy = VerificationPolicy::ACCEPT;
+ callVerificationFailedCallback(suffix, policy);
+ policies[suffix] = policy;
+ }
+
+ return policies;
+}
+
+Verifier::PolicyMap VoidVerifier::verifyPackets(
+ const std::vector<PacketPtr> &packets, const SuffixMap &suffix_map) {
+ return verifyPackets(packets);
+}
+
+// ---------------------------------------------------------
+// Asymmetric Verifier
+// ---------------------------------------------------------
+AsymmetricVerifier::AsymmetricVerifier(std::shared_ptr<EVP_PKEY> key) {
+ setKey(key);
+}
+
+AsymmetricVerifier::AsymmetricVerifier(const std::string &cert_path) {
+ useCertificate(cert_path);
+}
+
+AsymmetricVerifier::AsymmetricVerifier(std::shared_ptr<X509> cert) {
+ useCertificate(cert);
+}
+
+void AsymmetricVerifier::setKey(std::shared_ptr<EVP_PKEY> key) { key_ = key; };
+
+void AsymmetricVerifier::useCertificate(const std::string &cert_path) {
+ FILE *certf = fopen(cert_path.c_str(), "rb");
+
+ if (certf == nullptr) {
+ throw errors::RuntimeException("Certificate not found");
+ }
+
+ std::shared_ptr<X509> cert = std::shared_ptr<X509>(
+ PEM_read_X509(certf, nullptr, nullptr, nullptr), ::X509_free);
+ useCertificate(cert);
+
+ fclose(certf);
+}
+
+void AsymmetricVerifier::useCertificate(std::shared_ptr<X509> cert) {
+ key_ =
+ std::shared_ptr<EVP_PKEY>(X509_get_pubkey(cert.get()), ::EVP_PKEY_free);
+}
+
+bool AsymmetricVerifier::verifyBuffer(const uint8_t *buffer, std::size_t len,
+ const utils::MemBuf::Ptr &signature,
+ CryptoSuite suite) {
+ const EVP_MD *hash_md = getMD(suite);
+
+ std::shared_ptr<EVP_MD_CTX> md_ctx(EVP_MD_CTX_new(), EVP_MD_CTX_free);
+ if (md_ctx == nullptr) {
+ throw errors::RuntimeException("Signature context allocation failed");
+ }
+
+ if (EVP_DigestVerifyInit(md_ctx.get(), nullptr, hash_md, nullptr,
+ key_.get()) != 1) {
+ throw errors::RuntimeException("Signature initialization failed");
+ }
+
+ return EVP_DigestVerify(md_ctx.get(), signature->data(), signature->length(),
+ buffer, len) == 1;
+};
+
+bool AsymmetricVerifier::verifyBuffer(const std::vector<uint8_t> &buffer,
+ const utils::MemBuf::Ptr &signature,
+ CryptoSuite suite) {
+ return verifyBuffer(buffer.data(), buffer.size(), signature, suite);
+}
+
+bool AsymmetricVerifier::verifyBuffer(const utils::MemBuf *buffer,
+ const utils::MemBuf::Ptr &signature,
+ CryptoSuite suite) {
+ if (buffer->isChained()) {
+ throw errors::RuntimeException(
+ "Signature of chained membuf is not supported.");
+ }
+
+ return verifyBuffer(buffer->data(), buffer->length(), signature, suite);
+}
+
+// ---------------------------------------------------------
+// Symmetric Verifier
+// ---------------------------------------------------------
+SymmetricVerifier::SymmetricVerifier(const std::string &passphrase) {
+ setPassphrase(passphrase);
+}
+
+// Create and set a symmetric key from a passphrase.
+void SymmetricVerifier::setPassphrase(const std::string &passphrase) {
+ key_ = std::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);
+}
+
+bool SymmetricVerifier::verifyBuffer(const uint8_t *buffer, std::size_t len,
+ const utils::MemBuf::Ptr &signature,
+ CryptoSuite suite) {
+ const EVP_MD *hash_md = getMD(suite);
+ if (hash_md == nullptr) {
+ throw errors::RuntimeException("Unknown hash type");
+ }
+
+ const utils::MemBuf::Ptr &signature_bis =
+ core::PacketManager<>::getInstance().getMemBuf();
+ size_t signature_bis_len;
+
+ std::shared_ptr<EVP_MD_CTX> md_ctx(EVP_MD_CTX_new(), EVP_MD_CTX_free);
+ if (md_ctx == nullptr) {
+ throw errors::RuntimeException("Signature context allocation failed");
+ }
+
+ if (EVP_DigestSignInit(md_ctx.get(), nullptr, hash_md, nullptr, key_.get()) !=
+ 1) {
+ throw errors::RuntimeException("Signature initialization failed");
+ }
+
+ if (EVP_DigestSign(md_ctx.get(), nullptr, &signature_bis_len, buffer, len) !=
+ 1) {
+ throw errors::RuntimeException("Signature length computation failed");
+ };
+
+ DCHECK(signature_bis_len <= signature_bis->tailroom());
+ signature_bis->append(signature_bis_len);
+
+ if (EVP_DigestSign(md_ctx.get(), signature_bis->writableData(),
+ &signature_bis_len, buffer, len) != 1) {
+ throw errors::RuntimeException("Signature computation failed");
+ };
+
+ DCHECK(signature_bis_len <= signature_bis->tailroom());
+ signature_bis->setLength(signature_bis_len);
+
+ return signature->length() == signature_bis_len &&
+ *signature == *signature_bis;
+}
+
+bool SymmetricVerifier::verifyBuffer(const std::vector<uint8_t> &buffer,
+ const utils::MemBuf::Ptr &signature,
+ CryptoSuite suite) {
+ return verifyBuffer(buffer.data(), buffer.size(), signature, suite);
+}
+
+bool SymmetricVerifier::verifyBuffer(const utils::MemBuf *buffer,
+ const utils::MemBuf::Ptr &signature,
+ CryptoSuite suite) {
+ if (buffer->isChained()) {
+ throw errors::RuntimeException(
+ "Signature of chained membuf is not supported.");
+ }
+
+ return verifyBuffer(buffer->data(), buffer->length(), signature, suite);
+}
+
+} // namespace auth
+} // namespace transport