summaryrefslogtreecommitdiffstats
path: root/libtransport/src/security
diff options
context:
space:
mode:
Diffstat (limited to 'libtransport/src/security')
-rw-r--r--libtransport/src/security/CMakeLists.txt22
-rw-r--r--libtransport/src/security/identity.cc115
-rw-r--r--libtransport/src/security/signer.cc187
-rw-r--r--libtransport/src/security/verifier.cc241
4 files changed, 565 insertions, 0 deletions
diff --git a/libtransport/src/security/CMakeLists.txt b/libtransport/src/security/CMakeLists.txt
new file mode 100644
index 000000000..0e7b5832b
--- /dev/null
+++ b/libtransport/src/security/CMakeLists.txt
@@ -0,0 +1,22 @@
+# 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/signer.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/verifier.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/identity.cc
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
diff --git a/libtransport/src/security/identity.cc b/libtransport/src/security/identity.cc
new file mode 100644
index 000000000..55713245e
--- /dev/null
+++ b/libtransport/src/security/identity.cc
@@ -0,0 +1,115 @@
+/*
+ * 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/security/identity.h>
+
+extern "C" {
+#include <parc/security/parc_PublicKeySigner.h>
+#include <parc/security/parc_Security.h>
+}
+
+namespace utils {
+
+Identity::Identity(const std::string &keystore_name,
+ const std::string &keystore_password, CryptoSuite suite,
+ unsigned int key_length, unsigned int validity_days,
+ const std::string &subject_name) {
+ parcSecurity_Init();
+
+ bool success = parcPkcs12KeyStore_CreateFile(
+ keystore_name.c_str(), keystore_password.c_str(), subject_name.c_str(),
+ parcCryptoSuite_GetSigningAlgorithm(static_cast<PARCCryptoSuite>(suite)),
+ key_length, validity_days);
+
+ parcAssertTrue(
+ success,
+ "parcPkcs12KeyStore_CreateFile('%s', '%s', '%s', %d, %d) failed.",
+ keystore_name.c_str(), keystore_password.c_str(), subject_name.c_str(),
+ static_cast<int>(key_length), validity_days);
+
+ PARCIdentityFile *identity_file =
+ parcIdentityFile_Create(keystore_name.c_str(), keystore_password.c_str());
+
+ identity_ =
+ parcIdentity_Create(identity_file, PARCIdentityFileAsPARCIdentity);
+
+ PARCSigner *signer = parcIdentity_CreateSigner(
+ identity_,
+ parcCryptoSuite_GetCryptoHash(static_cast<PARCCryptoSuite>(suite)));
+
+ signer_ = std::make_shared<Signer>(signer, suite);
+
+ parcSigner_Release(&signer);
+ parcIdentityFile_Release(&identity_file);
+}
+
+Identity::Identity(const Identity &other)
+ : signer_(other.signer_), hash_algorithm_(other.hash_algorithm_) {
+ parcSecurity_Init();
+ identity_ = parcIdentity_Acquire(other.identity_);
+}
+
+Identity Identity::generateIdentity(const std::string &subject_name) {
+ std::string keystore_name = "keystore";
+ std::string keystore_password = "password";
+ std::size_t key_length = 1024;
+ unsigned int validity_days = 30;
+ CryptoSuite suite = CryptoSuite::RSA_SHA256;
+
+ return utils::Identity(keystore_name, keystore_password, suite,
+ (unsigned int)key_length, validity_days, subject_name);
+}
+
+Identity::Identity(std::string &file_name, std::string &password,
+ transport::core::HashAlgorithm hash_algorithm)
+ : hash_algorithm_(hash_algorithm) {
+ parcSecurity_Init();
+
+ PARCIdentityFile *identity_file =
+ parcIdentityFile_Create(file_name.c_str(), password.c_str());
+
+ identity_ =
+ parcIdentity_Create(identity_file, PARCIdentityFileAsPARCIdentity);
+
+ PARCSigner *signer = parcIdentity_CreateSigner(
+ identity_, static_cast<PARCCryptoHashType>(hash_algorithm));
+
+ signer_ = std::make_shared<Signer>(
+ signer, CryptoSuite(parcSigner_GetCryptoSuite(signer)));
+
+ parcSigner_Release(&signer);
+ parcIdentityFile_Release(&identity_file);
+}
+
+Identity::~Identity() {
+ parcIdentity_Release(&identity_);
+ parcSecurity_Fini();
+}
+
+std::string Identity::getFileName() {
+ return std::string(parcIdentity_GetFileName(identity_));
+}
+
+std::string Identity::getPassword() {
+ return std::string(parcIdentity_GetPassWord(identity_));
+}
+
+std::shared_ptr<Signer> Identity::getSigner() { return signer_; }
+
+size_t Identity::getSignatureLength() const {
+ return signer_->getSignatureLength();
+}
+
+} // namespace utils
diff --git a/libtransport/src/security/signer.cc b/libtransport/src/security/signer.cc
new file mode 100644
index 000000000..314c3ea82
--- /dev/null
+++ b/libtransport/src/security/signer.cc
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright 2017 Facebook, Inc.
+ *
+ * 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/errors/malformed_ahpacket_exception.h>
+#include <hicn/transport/security/key_id.h>
+#include <hicn/transport/security/signer.h>
+#include <hicn/transport/utils/membuf.h>
+
+extern "C" {
+#ifndef _WIN32
+TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat")
+#endif
+#include <hicn/hicn.h>
+#include <parc/security/parc_PublicKeySigner.h>
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_SymmetricKeySigner.h>
+}
+
+#include <chrono>
+
+#define ALLOW_UNALIGNED_READS 1
+
+namespace utils {
+
+uint8_t Signer::zeros[200] = {0};
+
+/*One signer_ per Private Key*/
+Signer::Signer(PARCKeyStore *keyStore, CryptoSuite suite) {
+ parcSecurity_Init();
+
+ switch (suite) {
+ case CryptoSuite::DSA_SHA256:
+ case CryptoSuite::RSA_SHA256:
+ case CryptoSuite::RSA_SHA512:
+ case CryptoSuite::ECDSA_256K1: {
+ this->signer_ =
+ parcSigner_Create(parcPublicKeySigner_Create(
+ keyStore, static_cast<PARCCryptoSuite>(suite)),
+ PARCPublicKeySignerAsSigner);
+ break;
+ }
+ case CryptoSuite::HMAC_SHA256:
+ case CryptoSuite::HMAC_SHA512: {
+ this->signer_ =
+ parcSigner_Create(parcSymmetricKeySigner_Create(
+ (PARCSymmetricKeyStore *)keyStore,
+ parcCryptoSuite_GetCryptoHash(
+ static_cast<PARCCryptoSuite>(suite))),
+ PARCSymmetricKeySignerAsSigner);
+ break;
+ }
+ default: { return; }
+ }
+
+ suite_ = suite;
+ key_id_ = parcSigner_CreateKeyId(this->signer_);
+ signature_length_ = parcSigner_GetSignatureSize(this->signer_);
+}
+
+Signer::Signer(const std::string &passphrase, CryptoSuite suite) {
+ parcSecurity_Init();
+
+ switch (suite) {
+ case CryptoSuite::HMAC_SHA256:
+ case CryptoSuite::HMAC_SHA512: {
+ composer_ = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer_, passphrase.c_str());
+ key_buffer_ = parcBufferComposer_ProduceBuffer(composer_);
+ symmetricKeyStore_ = parcSymmetricKeyStore_Create(key_buffer_);
+ this->signer_ = parcSigner_Create(
+ parcSymmetricKeySigner_Create(
+ symmetricKeyStore_, parcCryptoSuite_GetCryptoHash(
+ static_cast<PARCCryptoSuite>(suite))),
+ PARCSymmetricKeySignerAsSigner);
+ break;
+ }
+ default: { return; }
+ }
+
+ suite_ = suite;
+ key_id_ = parcSigner_CreateKeyId(this->signer_);
+ signature_length_ = parcSigner_GetSignatureSize(this->signer_);
+}
+
+Signer::Signer(const PARCSigner *signer, CryptoSuite suite)
+ : signer_(parcSigner_Acquire(signer)),
+ key_id_(parcSigner_CreateKeyId(this->signer_)),
+ suite_(suite),
+ signature_length_(parcSigner_GetSignatureSize(this->signer_)) {
+ parcSecurity_Init();
+}
+
+Signer::Signer(const PARCSigner *signer)
+ : Signer(signer, CryptoSuite::UNKNOWN) {}
+
+Signer::~Signer() {
+ if (signature_) parcSignature_Release(&signature_);
+ if (symmetricKeyStore_) parcSymmetricKeyStore_Release(&symmetricKeyStore_);
+ if (key_buffer_) parcBuffer_Release(&key_buffer_);
+ if (composer_) parcBufferComposer_Release(&composer_);
+ if (signer_) parcSigner_Release(&signer_);
+ if (key_id_) parcKeyId_Release(&key_id_);
+ parcSecurity_Fini();
+}
+
+void Signer::sign(Packet &packet) {
+ // header chain points to the IP + TCP hicn header + AH Header
+ MemBuf *header_chain = packet.header_head_;
+ MemBuf *payload_chain = packet.payload_head_;
+ uint8_t *hicn_packet = (uint8_t *)header_chain->writableData();
+ Packet::Format format = packet.getFormat();
+
+ if (!(format & HFO_AH)) {
+ throw errors::MalformedAHPacketException();
+ }
+
+ packet.setSignatureSize(signature_length_);
+
+ // Copy IP+TCP/ICMP header before zeroing them
+ hicn_header_t header_copy;
+ hicn_packet_copy_header(format, (const hicn_header_t *)packet.packet_start_,
+ &header_copy, false);
+
+ std::size_t header_len = Packet::getHeaderSizeFromFormat(format);
+
+ packet.resetForHash();
+
+ /* Fill the hicn_ah header */
+ using namespace std::chrono;
+ auto now = duration_cast<milliseconds>(system_clock::now().time_since_epoch())
+ .count();
+ packet.setSignatureTimestamp(now);
+ packet.setValidationAlgorithm(suite_);
+
+ KeyId key_id;
+ key_id.first = (uint8_t *)parcBuffer_Overlay(
+ (PARCBuffer *)parcKeyId_GetKeyId(this->key_id_), 0);
+ packet.setKeyId(key_id);
+
+ // Calculate hash
+ CryptoHasher hasher(parcSigner_GetCryptoHasher(signer_));
+ hasher.init();
+ hasher.updateBytes(hicn_packet, header_len + signature_length_);
+
+ for (MemBuf *current = payload_chain; current != header_chain;
+ current = current->next()) {
+ hasher.updateBytes(current->data(), current->length());
+ }
+
+ CryptoHash hash = hasher.finalize();
+
+ signature_ = parcSigner_SignDigestNoAlloc(this->signer_, hash.hash_,
+ packet.getSignature(),
+ (uint32_t)signature_length_);
+ PARCBuffer *buffer = parcSignature_GetSignature(signature_);
+
+ size_t bytes_len = parcBuffer_Remaining(buffer);
+
+ if (bytes_len > signature_length_) {
+ throw errors::MalformedAHPacketException();
+ }
+
+ hicn_packet_copy_header(format, &header_copy,
+ (hicn_header_t *)packet.packet_start_, false);
+}
+
+size_t Signer::getSignatureLength() { return signature_length_; }
+
+PARCKeyStore *Signer::getKeyStore() {
+ return parcSigner_GetKeyStore(this->signer_);
+}
+
+} // namespace utils
diff --git a/libtransport/src/security/verifier.cc b/libtransport/src/security/verifier.cc
new file mode 100644
index 000000000..19796f718
--- /dev/null
+++ b/libtransport/src/security/verifier.cc
@@ -0,0 +1,241 @@
+/*
+ * 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/security/key_id.h>
+#include <hicn/transport/security/verifier.h>
+#include <hicn/transport/utils/log.h>
+
+extern "C" {
+#ifndef _WIN32
+TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat")
+#endif
+#include <hicn/hicn.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);
+}
+
+Verifier::~Verifier() {
+ if (key_) parcKey_Release(&key_);
+ if (keyId_) parcKeyId_Release(&keyId_);
+ if (signer_) parcSigner_Release(&signer_);
+ if (symmetricKeyStore_) parcSymmetricKeyStore_Release(&symmetricKeyStore_);
+ if (key_buffer_) parcBuffer_Release(&key_buffer_);
+ if (composer_) parcBufferComposer_Release(&composer_);
+ if (certificate_) parcCertificate_Release(&certificate_);
+ if (factory_) parcCertificateFactory_Release(&factory_);
+ if (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::addKeyFromPassphrase(const std::string &passphrase,
+ CryptoSuite suite) {
+ composer_ = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer_, passphrase.c_str());
+ key_buffer_ = parcBufferComposer_ProduceBuffer(composer_);
+
+ symmetricKeyStore_ = parcSymmetricKeyStore_Create(key_buffer_);
+ signer_ = parcSigner_Create(
+ parcSymmetricKeySigner_Create(
+ symmetricKeyStore_,
+ parcCryptoSuite_GetCryptoHash(static_cast<PARCCryptoSuite>(suite))),
+ PARCSymmetricKeySignerAsSigner);
+ keyId_ = parcSigner_CreateKeyId(signer_);
+ key_ = parcKey_CreateFromSymmetricKey(
+ keyId_, parcSigner_GetSigningAlgorithm(signer_), key_buffer_);
+
+ addKey(key_);
+ return keyId_;
+}
+
+PARCKeyId *Verifier::addKeyFromCertificate(const std::string &file_name) {
+ 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;
+ }
+
+ certificate_ = parcCertificateFactory_CreateCertificateFromFile(
+ factory_, (char *)file_name.c_str(), NULL);
+ PARCBuffer *derEncodedVersion =
+ parcCertificate_GetDEREncodedPublicKey(certificate_);
+ PARCCryptoHash *keyDigest = parcCertificate_GetPublicKeyDigest(certificate_);
+ keyId_ = parcKeyId_Create(parcCryptoHash_GetDigest(keyDigest));
+ key_ = parcKey_CreateFromDerEncodedPublicKey(keyId_, PARCSigningAlgorithm_RSA,
+ derEncodedVersion);
+
+ addKey(key_);
+ return keyId_;
+}
+
+int Verifier::verify(const Packet &packet) {
+ // to initialize packet.payload_head_
+ const_cast<Packet *>(&packet)->separateHeaderPayload();
+ bool valid = false;
+
+ // initialize packet.payload_head_
+ const_cast<Packet *>(&packet)->separateHeaderPayload();
+ // 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;
+ hicn_packet_copy_header(format, (const hicn_header_t *)packet.packet_start_,
+ &header_copy, false);
+
+ PARCCryptoSuite suite =
+ static_cast<PARCCryptoSuite>(packet.getValidationAlgorithm());
+ PARCCryptoHashType hashtype = parcCryptoSuite_GetCryptoHash(suite);
+ 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 = (int)packet.getSignatureSize();
+ uint8_t *_signature = packet.getSignature();
+ uint8_t *signature = new uint8_t[ah_payload_len];
+ // TODO Remove signature copy at this point, by not setting to zero
+ // the validation payload.
+ std::memcpy(signature, _signature, ah_payload_len);
+
+ std::shared_ptr<CryptoHasher> hasher;
+ switch (CryptoSuite(suite)) {
+ case CryptoSuite::DSA_SHA256:
+ case CryptoSuite::RSA_SHA256:
+ case CryptoSuite::RSA_SHA512:
+ case CryptoSuite::ECDSA_256K1: {
+ hasher = std::make_shared<CryptoHasher>(
+ parcVerifier_GetCryptoHasher(verifier_, key_id, hashtype));
+ break;
+ }
+ case CryptoSuite::HMAC_SHA256:
+ case CryptoSuite::HMAC_SHA512: {
+ if (!signer_) return false;
+ hasher =
+ std::make_shared<CryptoHasher>(parcSigner_GetCryptoHasher(signer_));
+ break;
+ }
+ default: { return false; }
+ }
+ CryptoHash hash_computed_locally = getPacketHash(packet, hasher);
+
+ 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.hash_, suite, signatureToVerify);
+
+ /* Restore the resetted fields */
+ hicn_packet_copy_header(format, &header_copy,
+ (hicn_header_t *)packet.packet_start_, false);
+
+ delete[] signature;
+ parcKeyId_Release(&key_id);
+ parcBuffer_Release(&bits);
+ parcSignature_Release(&signatureToVerify);
+
+ return valid;
+}
+
+CryptoHash Verifier::getPacketHash(const Packet &packet,
+ std::shared_ptr<CryptoHasher> hasher) {
+ MemBuf *header_chain = packet.header_head_;
+ MemBuf *payload_chain = packet.payload_head_;
+ Packet::Format format = packet.getFormat();
+ int ah_payload_len = (int)packet.getSignatureSize();
+ uint8_t *hicn_packet = header_chain->writableData();
+ std::size_t header_len = Packet::getHeaderSizeFromFormat(format);
+
+ // Reset fields that should not appear in the signature
+ const_cast<Packet &>(packet).resetForHash();
+ hasher->init().updateBytes(hicn_packet, header_len + ah_payload_len);
+
+ for (MemBuf *current = payload_chain; current != header_chain;
+ current = current->next()) {
+ hasher->updateBytes(current->data(), current->length());
+ }
+
+ return hasher->finalize();
+}
+
+} // namespace utils