aboutsummaryrefslogtreecommitdiffstats
path: root/libtransport/src/hicn/transport/utils/verifier.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libtransport/src/hicn/transport/utils/verifier.cc')
-rwxr-xr-xlibtransport/src/hicn/transport/utils/verifier.cc193
1 files changed, 193 insertions, 0 deletions
diff --git a/libtransport/src/hicn/transport/utils/verifier.cc b/libtransport/src/hicn/transport/utils/verifier.cc
new file mode 100755
index 000000000..9a3de43c1
--- /dev/null
+++ b/libtransport/src/hicn/transport/utils/verifier.cc
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2017-2019 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/core/packet.h>
+#include <hicn/transport/errors/malformed_ahpacket_exception.h>
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/key_id.h>
+#include <hicn/transport/utils/log.h>
+#include <hicn/transport/utils/verifier.h>
+
+extern "C" {
+TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat")
+#include <hicn/hicn.h>
+#include <parc/security/parc_CertificateFactory.h>
+#include <parc/security/parc_InMemoryVerifier.h>
+#include <parc/security/parc_Security.h>
+}
+
+#include <sys/stat.h>
+
+namespace utils {
+
+TRANSPORT_ALWAYS_INLINE bool file_exists(const std::string &name) {
+ struct stat buffer;
+ return (stat(name.c_str(), &buffer) == 0);
+}
+
+uint8_t Verifier::zeros[200] = {0};
+
+Verifier::Verifier() {
+ parcSecurity_Init();
+ PARCInMemoryVerifier *in_memory_verifier = parcInMemoryVerifier_Create();
+ this->verifier_ =
+ parcVerifier_Create(in_memory_verifier, PARCInMemoryVerifierAsVerifier);
+ parcInMemoryVerifier_Release(&in_memory_verifier);
+}
+
+Verifier::~Verifier() {
+ parcVerifier_Release(&verifier_);
+ parcSecurity_Fini();
+}
+
+/*
+ * TODO: Unsupported in libparc
+ */
+bool Verifier::hasKey(PARCKeyId *keyId) { return false; }
+
+/*
+ * TODO: signal errors without trap.
+ */
+bool Verifier::addKey(PARCKey *key) {
+ parcVerifier_AddKey(this->verifier_, key);
+ return true;
+}
+
+PARCKeyId * Verifier::addKeyFromCertificate(const std::string &file_name) {
+ PARCCertificateFactory *factory = parcCertificateFactory_Create(PARCCertificateType_X509,
+ PARCContainerEncoding_PEM);
+ parcAssertNotNull(factory, "Expected non-NULL factory");
+
+ if (!file_exists(file_name)) {
+ TRANSPORT_LOGW("Warning! The certificate %s file does not exist",
+ file_name.c_str());
+ return nullptr;
+ }
+
+ PARCCertificate *certificate =
+ parcCertificateFactory_CreateCertificateFromFile(
+ factory, (char *)file_name.c_str(), NULL);
+
+ PARCKey *key = parcCertificate_GetPublicKey(certificate);
+ addKey(key);
+
+ PARCKeyId *ret = parcKeyId_Acquire(parcKey_GetKeyId(key));
+
+ // parcKey_Release(&key);
+ // parcCertificate_Release(&certificate);
+ // parcCertificateFactory_Release(&factory);
+
+ return ret;
+}
+
+int Verifier::verify(const Packet &packet) {
+ bool valid = false;
+
+ // header chain points to the IP + TCP hicn header
+ utils::MemBuf *header_chain = packet.header_head_;
+ utils::MemBuf *payload_chain = packet.payload_head_;
+ uint8_t *hicn_packet = header_chain->writableData();
+ Packet::Format format = packet.getFormat();
+
+ if (!(packet.format_ & HFO_AH)) {
+ throw errors::MalformedAHPacketException();
+ }
+
+ // Copy IP+TCP/ICMP header before zeroing them
+ hicn_header_t header_copy;
+ if (format & HFO_INET) {
+ memcpy(&header_copy, hicn_packet, sizeof(hicn_v4_hdr_t));
+ } else if (format & HFO_INET6) {
+ memcpy(&header_copy, hicn_packet, sizeof(hicn_v6_hdr_t));
+ }
+
+ std::size_t header_len = Packet::getHeaderSizeFromFormat(format);
+
+ PARCCryptoSuite suite =
+ static_cast<PARCCryptoSuite>(packet.getValidationAlgorithm());
+ KeyId _key_id = packet.getKeyId();
+ PARCBuffer *buffer =
+ parcBuffer_Wrap(_key_id.first, _key_id.second, 0, _key_id.second);
+ PARCKeyId *key_id = parcKeyId_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ int ah_payload_len = header_chain->next()->length();
+ uint8_t *signature = header_chain->next()->writableData();
+
+ // Reset fields that should not appear in the signature
+ const_cast<Packet &>(packet).resetForHash();
+
+ PARCCryptoHashType hashtype = parcCryptoSuite_GetCryptoHash(suite);
+ utils::CryptoHasher hasher(
+ parcVerifier_GetCryptoHasher(verifier_, key_id, hashtype));
+
+ hasher.init()
+ .updateBytes(hicn_packet, header_len)
+ .updateBytes(zeros, ah_payload_len);
+
+ for (utils::MemBuf *current = payload_chain; current != header_chain;
+ current = current->next()) {
+ hasher.updateBytes(current->data(), current->length());
+ }
+
+ utils::CryptoHash hash = hasher.finalize();
+ PARCCryptoHash *hash_computed_locally = hash.hash_;
+
+ PARCBuffer *bits =
+ parcBuffer_Wrap(signature, ah_payload_len, 0, ah_payload_len);
+ parcBuffer_Rewind(bits);
+
+ /* IF the signature algo is ECDSA, the signature might be shorter than the
+ * signature field */
+ PARCSigningAlgorithm algo = parcCryptoSuite_GetSigningAlgorithm(suite);
+ while (algo == PARCSigningAlgorithm_ECDSA && parcBuffer_HasRemaining(bits) &&
+ parcBuffer_GetUint8(bits) == 0)
+ ;
+
+ if (algo == PARCSigningAlgorithm_ECDSA) {
+ parcBuffer_SetPosition(bits, parcBuffer_Position(bits) - 1);
+ }
+
+ if (!parcBuffer_HasRemaining(bits)) {
+ parcKeyId_Release(&key_id);
+ parcBuffer_Release(&bits);
+ return valid;
+ }
+
+ PARCSignature *signatureToVerify = parcSignature_Create(
+ parcCryptoSuite_GetSigningAlgorithm(suite), hashtype, bits);
+
+ if (algo == PARCSigningAlgorithm_RSA) {
+ parcBuffer_SetPosition(bits, 0);
+ }
+
+ valid = parcVerifier_VerifyDigestSignature(
+ verifier_, key_id, hash_computed_locally, suite, signatureToVerify);
+
+ /* Restore the resetted fields */
+ if (format & HFO_INET) {
+ memcpy(hicn_packet, &header_copy, sizeof(hicn_v4_hdr_t));
+ } else if (format & HFO_INET6) {
+ memcpy(hicn_packet, &header_copy, sizeof(hicn_v6_hdr_t));
+ }
+
+ parcKeyId_Release(&key_id);
+
+ parcBuffer_Release(&bits);
+ parcSignature_Release(&signatureToVerify);
+
+ return valid;
+}
+} // namespace utils