diff options
Diffstat (limited to 'libtransport/src/auth')
-rw-r--r-- | libtransport/src/auth/CMakeLists.txt | 4 | ||||
-rw-r--r-- | libtransport/src/auth/crypto_hash.cc | 201 | ||||
-rw-r--r-- | libtransport/src/auth/crypto_suite.cc | 81 | ||||
-rw-r--r-- | libtransport/src/auth/identity.cc | 286 | ||||
-rw-r--r-- | libtransport/src/auth/signer.cc | 277 | ||||
-rw-r--r-- | libtransport/src/auth/verifier.cc | 427 |
6 files changed, 901 insertions, 375 deletions
diff --git a/libtransport/src/auth/CMakeLists.txt b/libtransport/src/auth/CMakeLists.txt index 0e7b5832b..699bc1050 100644 --- a/libtransport/src/auth/CMakeLists.txt +++ b/libtransport/src/auth/CMakeLists.txt @@ -11,12 +11,12 @@ # 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 + ${CMAKE_CURRENT_SOURCE_DIR}/crypto_hash.cc + ${CMAKE_CURRENT_SOURCE_DIR}/crypto_suite.cc ) set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) diff --git a/libtransport/src/auth/crypto_hash.cc b/libtransport/src/auth/crypto_hash.cc new file mode 100644 index 000000000..b4b0a8b81 --- /dev/null +++ b/libtransport/src/auth/crypto_hash.cc @@ -0,0 +1,201 @@ +/* + * 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/auth/crypto_hash.h> + +using namespace std; + +namespace transport { +namespace auth { + +CryptoHash::CryptoHash() : CryptoHash(CryptoHashType::UNKNOWN) {} + +CryptoHash::CryptoHash(const CryptoHash &other) + : digest_type_(other.digest_type_), + digest_(other.digest_), + digest_size_(other.digest_size_) {} + +CryptoHash::CryptoHash(CryptoHash &&other) + : digest_type_(move(other.digest_type_)), + digest_(other.digest_), + digest_size_(other.digest_size_) { + other.reset(); +} + +CryptoHash::CryptoHash(CryptoHashType hash_type) { setType(hash_type); } + +CryptoHash::CryptoHash(const uint8_t *hash, size_t size, + CryptoHashType hash_type) + : digest_type_(hash_type), digest_size_(size) { + digest_.resize(size); + memcpy(digest_.data(), hash, size); +} + +CryptoHash::CryptoHash(const vector<uint8_t> &hash, CryptoHashType hash_type) + : CryptoHash(hash.data(), hash.size(), hash_type) {} + +CryptoHash &CryptoHash::operator=(const CryptoHash &other) { + digest_type_ = other.digest_type_; + digest_ = other.digest_; + digest_size_ = other.digest_size_; + return *this; +} + +bool CryptoHash::operator==(const CryptoHash &other) const { + return (digest_type_ == other.digest_type_ && digest_ == other.digest_); +} + +void CryptoHash::computeDigest(const uint8_t *buffer, size_t len) { + CryptoHashEVP hash_evp = CryptoHash::getEVP(digest_type_); + + if (hash_evp == nullptr) { + throw errors::RuntimeException("Unknown hash type"); + } + + EVP_Digest(buffer, len, digest_.data(), (unsigned int *)&digest_size_, + (*hash_evp)(), nullptr); +} + +void CryptoHash::computeDigest(const vector<uint8_t> &buffer) { + computeDigest(buffer.data(), buffer.size()); +} + +void CryptoHash::computeDigest(const utils::MemBuf *buffer) { + CryptoHashEVP hash_evp = CryptoHash::getEVP(digest_type_); + + if (hash_evp == nullptr) { + throw errors::RuntimeException("Unknown hash type"); + } + + EVP_MD_CTX *mcdtx = EVP_MD_CTX_new(); + const utils::MemBuf *p = buffer; + + if (EVP_DigestInit_ex(mcdtx, (*hash_evp)(), nullptr) == 0) { + throw errors::RuntimeException("Digest initialization failed"); + } + + do { + if (EVP_DigestUpdate(mcdtx, p->data(), p->length()) != 1) { + throw errors::RuntimeException("Digest update failed"); + } + + p = p->next(); + } while (p != buffer); + + if (EVP_DigestFinal_ex(mcdtx, digest_.data(), + (unsigned int *)&digest_size_) != 1) { + throw errors::RuntimeException("Digest computation failed"); + } + + EVP_MD_CTX_free(mcdtx); +} + +vector<uint8_t> CryptoHash::getDigest() const { return digest_; } + +string CryptoHash::getStringDigest() const { + stringstream string_digest; + + string_digest << hex << setfill('0'); + + for (auto byte : digest_) { + string_digest << hex << setw(2) << static_cast<int>(byte); + } + + return string_digest.str(); +} + +CryptoHashType CryptoHash::getType() const { return digest_type_; } + +size_t CryptoHash::getSize() const { return digest_size_; } + +void CryptoHash::setType(CryptoHashType hash_type) { + reset(); + digest_type_ = hash_type; + digest_size_ = CryptoHash::getSize(hash_type); + digest_.resize(digest_size_); +} + +void CryptoHash::display() { + switch (digest_type_) { + case CryptoHashType::SHA256: + cout << "SHA256"; + break; + case CryptoHashType::SHA512: + cout << "SHA512"; + break; + case CryptoHashType::BLAKE2S256: + cout << "BLAKE2s256"; + break; + case CryptoHashType::BLAKE2B512: + cout << "BLAKE2b512"; + break; + default: + cout << "UNKNOWN"; + break; + } + + cout << ": " << getStringDigest() << endl; +} + +void CryptoHash::reset() { + digest_type_ = CryptoHashType::UNKNOWN; + digest_.clear(); + digest_size_ = 0; +} + +CryptoHashEVP CryptoHash::getEVP(CryptoHashType hash_type) { + switch (hash_type) { + case CryptoHashType::SHA256: + return &EVP_sha256; + break; + case CryptoHashType::SHA512: + return &EVP_sha512; + break; + case CryptoHashType::BLAKE2S256: + return &EVP_blake2s256; + break; + case CryptoHashType::BLAKE2B512: + return &EVP_blake2b512; + break; + default: + return nullptr; + break; + } +} + +size_t CryptoHash::getSize(CryptoHashType hash_type) { + CryptoHashEVP hash_evp = CryptoHash::getEVP(hash_type); + + if (hash_evp == nullptr) { + return 0; + } + + return EVP_MD_size((*hash_evp)()); +} + +bool CryptoHash::compareDigest(const uint8_t *digest1, const uint8_t *digest2, + CryptoHashType hash_type) { + CryptoHashEVP hash_evp = CryptoHash::getEVP(hash_type); + + if (hash_evp == nullptr) { + return false; + } + + return !static_cast<bool>( + memcmp(digest1, digest2, CryptoHash::getSize(hash_type))); +} + +} // namespace auth +} // namespace transport diff --git a/libtransport/src/auth/crypto_suite.cc b/libtransport/src/auth/crypto_suite.cc new file mode 100644 index 000000000..7e898ef09 --- /dev/null +++ b/libtransport/src/auth/crypto_suite.cc @@ -0,0 +1,81 @@ +/* + * 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/auth/crypto_suite.h> + +namespace transport { +namespace auth { + +CryptoSuite getSuite(int nid) { + switch (nid) { + case NID_ecdsa_with_SHA256: + return CryptoSuite::ECDSA_SHA256; + break; + case NID_ecdsa_with_SHA512: + return CryptoSuite::ECDSA_SHA512; + break; + case NID_sha256WithRSAEncryption: + return CryptoSuite::RSA_SHA256; + break; + case NID_sha512WithRSAEncryption: + return CryptoSuite::RSA_SHA512; + break; + case NID_hmacWithSHA256: + return CryptoSuite::HMAC_SHA256; + break; + case NID_hmacWithSHA512: + return CryptoSuite::HMAC_SHA512; + break; + case NID_dsa_with_SHA256: + return CryptoSuite::DSA_SHA256; + break; + case NID_dsa_with_SHA512: + return CryptoSuite::DSA_SHA512; + break; + default: + return CryptoSuite::UNKNOWN; + break; + } +} + +CryptoHashType getHashType(CryptoSuite suite) { + switch (suite) { + case CryptoSuite::ECDSA_BLAKE2B512: + case CryptoSuite::RSA_BLAKE2B512: + case CryptoSuite::HMAC_BLAKE2B512: + case CryptoSuite::DSA_BLAKE2B512: + return CryptoHashType::BLAKE2B512; + case CryptoSuite::ECDSA_BLAKE2S256: + case CryptoSuite::RSA_BLAKE2S256: + case CryptoSuite::HMAC_BLAKE2S256: + case CryptoSuite::DSA_BLAKE2S256: + return CryptoHashType::BLAKE2S256; + case CryptoSuite::ECDSA_SHA256: + case CryptoSuite::RSA_SHA256: + case CryptoSuite::HMAC_SHA256: + case CryptoSuite::DSA_SHA256: + return CryptoHashType::SHA256; + case CryptoSuite::ECDSA_SHA512: + case CryptoSuite::RSA_SHA512: + case CryptoSuite::HMAC_SHA512: + case CryptoSuite::DSA_SHA512: + return CryptoHashType::SHA512; + default: + return CryptoHashType::UNKNOWN; + } +} + +} // namespace auth +} // namespace transport diff --git a/libtransport/src/auth/identity.cc b/libtransport/src/auth/identity.cc index bd787b9b6..f56532033 100644 --- a/libtransport/src/auth/identity.cc +++ b/libtransport/src/auth/identity.cc @@ -17,90 +17,262 @@ using namespace std; +// function needed to create the a certificate +static bool _addRandomSerial(X509 *cert) { + unsigned long serial = 0; + unsigned char serial_bytes[sizeof(serial)]; + + // Construct random positive serial number. + RAND_bytes(serial_bytes, sizeof(serial_bytes)); + serial_bytes[0] &= 0x7F; + serial = 0; + for (size_t i = 0; i < sizeof(serial_bytes); i++) { + serial = (256 * serial) + serial_bytes[i]; + } + ASN1_INTEGER_set(X509_get_serialNumber(cert), serial); + return true; +} + +static bool _addValidityPeriod(X509 *cert, size_t validityDays) { + // Set the validity from now for the specified number of days. + X509_gmtime_adj(X509_get_notBefore(cert), (long)0); + X509_gmtime_adj(X509_get_notAfter(cert), (long)(60 * 60 * 24 * validityDays)); + return true; +} + +static bool _addSubjectName(X509 *cert, const char *subjectname) { + // Set up the simple subject name and issuer name for the certificate. + X509_NAME *name = X509_get_subject_name(cert); + + if (X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, + (unsigned char *)subjectname, -1, -1, 0)) { + if (X509_set_issuer_name(cert, name)) { + return true; + } + } + return false; +} +static bool _addCertificateExtensionWithContext(X509 *cert, int nid, + const char *value) { + X509_EXTENSION *extension; + X509V3_CTX context; + + X509V3_set_ctx_nodb(&context); + X509V3_set_ctx(&context, cert, cert, NULL, NULL, 0); + extension = X509V3_EXT_conf_nid(NULL, &context, nid, value); + if (extension == NULL) { + return false; + } + X509_add_ext(cert, extension, -1); + X509_EXTENSION_free(extension); + return true; +} +static bool _addCertificateExtension(X509 *cert, int nid, const char *value) { + X509_EXTENSION *extension = X509V3_EXT_conf_nid(NULL, NULL, nid, value); + if (extension == NULL) { + return false; + } + X509_add_ext(cert, extension, -1); + X509_EXTENSION_free(extension); + return true; +} + +static bool _addExtensions(X509 *cert) { + // Add the necessary extensions. + if (_addCertificateExtension(cert, NID_basic_constraints, + "critical,CA:FALSE") == true) { + if (_addCertificateExtension( + cert, NID_key_usage, + "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment," + "keyAgreement") == true) { + if (_addCertificateExtension(cert, NID_ext_key_usage, "clientAuth") == + true) { + return true; + } + } + } + return false; +} +static bool _addKeyIdentifier(X509 *cert) { + unsigned char spkid[SHA256_DIGEST_LENGTH]; + char spkid_hex[1 + 2 * SHA256_DIGEST_LENGTH]; + if (ASN1_item_digest(ASN1_ITEM_rptr(X509_PUBKEY), EVP_sha256(), + X509_get_X509_PUBKEY(cert), spkid, NULL)) { + for (int i = 0; i < 32; i++) { + snprintf(&spkid_hex[2 * i], 3, "%02X", (unsigned)spkid[i]); + } + if (_addCertificateExtension(cert, NID_subject_key_identifier, spkid_hex) == + true) { + if (_addCertificateExtensionWithContext( + cert, NID_authority_key_identifier, "keyid:always") == true) { + return true; + } + } + } + return false; +} + namespace transport { namespace auth { Identity::Identity(const string &keystore_path, const string &keystore_pwd, CryptoSuite suite, unsigned int signature_len, unsigned int validity_days, const string &subject_name) - : identity_(nullptr), signer_(nullptr) { - parcSecurity_Init(); - - bool success = parcPkcs12KeyStore_CreateFile( - keystore_path.c_str(), keystore_pwd.c_str(), subject_name.c_str(), - parcCryptoSuite_GetSigningAlgorithm(static_cast<PARCCryptoSuite>(suite)), - signature_len, validity_days); + : cert_(X509_new(), ::X509_free) { + // create the file and complete it. + // first we create the certificate - parcAssertTrue( - success, - "parcPkcs12KeyStore_CreateFile('%s', '%s', '%s', %d, %d, %d) failed.", - keystore_path.c_str(), keystore_pwd.c_str(), subject_name.c_str(), - static_cast<int>(suite), static_cast<int>(signature_len), validity_days); + // to create the cert we will need a private key - PARCIdentityFile *identity_file = - parcIdentityFile_Create(keystore_path.c_str(), keystore_pwd.c_str()); + std::shared_ptr<EVP_PKEY> privateKey(EVP_PKEY_new(), EVP_PKEY_free); - identity_ = - parcIdentity_Create(identity_file, PARCIdentityFileAsPARCIdentity); + if (suite == CryptoSuite::RSA_SHA512 || suite == CryptoSuite::RSA_SHA256) { + RSA *rsa = RSA_new(); + BIGNUM *pub_exp; - PARCSigner *signer = parcIdentity_CreateSigner( - identity_, - parcCryptoSuite_GetCryptoHash(static_cast<PARCCryptoSuite>(suite))); + pub_exp = BN_new(); - signer_ = make_shared<AsymmetricSigner>(signer); - - parcSigner_Release(&signer); - parcIdentityFile_Release(&identity_file); + BN_set_word(pub_exp, RSA_F4); + if (1 != RSA_generate_key_ex(rsa, signature_len, pub_exp, NULL)) + throw errors::RuntimeException("can't generate the key"); + if (1 != EVP_PKEY_set1_RSA(privateKey.get(), rsa)) + throw errors::RuntimeException("can't generate the key"); + } else if (suite == CryptoSuite::ECDSA_SHA256) { + int curve_params; + switch (signature_len) { + case 160u: + curve_params = NID_secp160k1; + break; + case 192u: + curve_params = NID_secp192k1; + break; + case 224u: + curve_params = NID_secp224k1; + break; + case 256u: + curve_params = NID_secp256k1; + break; + default: + curve_params = -1; + break; + } + if (curve_params == -1) + throw errors::RuntimeException("can't generate the key"); + EC_KEY *ec_key = EC_KEY_new_by_curve_name(curve_params); + if (ec_key == NULL) + throw errors::RuntimeException("can't create ecdsa key from curve"); + EC_KEY_set_asn1_flag(ec_key, OPENSSL_EC_NAMED_CURVE); + if (EC_KEY_generate_key(ec_key) == 0) + throw errors::RuntimeException("can't generate the ecdsa key"); + if (EVP_PKEY_set1_EC_KEY(privateKey.get(), ec_key) == 0) + throw errors::RuntimeException("can't generate the ecdsa key"); + } else if (suite == CryptoSuite::DSA_SHA256) { + DSA *dsa = DSA_new(); + unsigned char buffer[32]; + if (RAND_bytes(buffer, sizeof(buffer)) != 1) { + throw errors::RuntimeException("can't generate the key"); + } + if (DSA_generate_parameters_ex(dsa, signature_len, buffer, sizeof(buffer), + NULL, NULL, NULL) != 1) + throw errors::RuntimeException("can't generate the key"); + if (DSA_generate_key(dsa) != 1) + throw errors::RuntimeException("can't generate the key"); + if (EVP_PKEY_set1_DSA(privateKey.get(), dsa) != 1) + throw errors::RuntimeException("can't generate the key"); + } + bool success = true; + success = success && (X509_set_version(cert_.get(), 2) == 1); // 2 => X509v3 + success = success && _addRandomSerial(cert_.get()); + success = success && _addValidityPeriod(cert_.get(), validity_days); + success = success && (X509_set_pubkey(cert_.get(), privateKey.get()) == 1); + success = success && _addSubjectName(cert_.get(), subject_name.c_str()); + success = success && _addExtensions(cert_.get()); + success = + success && (X509_sign(cert_.get(), privateKey.get(), EVP_sha256()) != 0); + success = success && _addKeyIdentifier(cert_.get()); + if (!success) { + throw errors::RuntimeException("error while creating the certificate"); + } + // the certificate is created. We create the pkcs12 object to write the p12 + // file + PKCS12 *p12 = PKCS12_create( + keystore_pwd.c_str(), "ccnxuser", privateKey.get(), cert_.get(), NULL, 0, + 0, 0 /*default iter*/, PKCS12_DEFAULT_ITER /*mac_iter*/, 0); + filename_ = keystore_path; + int fp = open(filename_.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0600); + if (fp == -1) throw errors::RuntimeException("impossible to create the file"); + FILE *fp_f = fdopen(fp, "wb"); + if (fp_f == NULL) + throw errors::RuntimeException("impossible to create the file"); + i2d_PKCS12_fp(fp_f, p12); + fclose(fp_f); + close(fp); + std::shared_ptr<EVP_PKEY> publickey(X509_get_pubkey(cert_.get()), + EVP_PKEY_free); + signer_ = std::shared_ptr<AsymmetricSigner>( + new AsymmetricSigner(suite, privateKey, publickey)); + signer_->signature_len_ = signature_len; } Identity::Identity(string &keystore_path, string &keystore_pwd, CryptoHashType hash_type) - : identity_(nullptr), signer_(nullptr) { - parcSecurity_Init(); - - PARCIdentityFile *identity_file = - parcIdentityFile_Create(keystore_path.c_str(), keystore_pwd.c_str()); - - identity_ = - parcIdentity_Create(identity_file, PARCIdentityFileAsPARCIdentity); - - PARCSigner *signer = parcIdentity_CreateSigner( - identity_, static_cast<PARCCryptoHashType>(hash_type)); - - signer_ = make_shared<AsymmetricSigner>(signer); - - parcSigner_Release(&signer); - parcIdentityFile_Release(&identity_file); + : cert_(X509_new(), ::X509_free) { + filename_ = keystore_path; + pwd_ = keystore_path; + // get the key and certificate by first opening the keystore file + FILE *p12file = fopen(keystore_path.c_str(), "r"); + if (p12file == NULL) + throw errors::RuntimeException("impossible open keystore"); + PKCS12 *p12 = d2i_PKCS12_fp(p12file, NULL); + EVP_PKEY *privatekey; + EVP_PKEY *publickey; + X509 *cert = cert_.get(); + // now we parse the file to get the first key and certificate + if (1 != PKCS12_parse(p12, keystore_pwd.c_str(), &privatekey, &cert, NULL)) + throw errors::RuntimeException("impossible to get the private key"); + publickey = X509_get_pubkey(cert); + // to have the cryptosuite we use the nid number that is used to identify the + // suite. + CryptoSuite suite = getSuite(X509_get_signature_nid(cert)); + signer_ = std::shared_ptr<AsymmetricSigner>(new AsymmetricSigner( + suite, std::shared_ptr<EVP_PKEY>(privatekey, EVP_PKEY_free), + std::shared_ptr<EVP_PKEY>(publickey, EVP_PKEY_free))); + PKCS12_free(p12); } -Identity::Identity(const Identity &other) - : identity_(nullptr), signer_(other.signer_) { - parcSecurity_Init(); - identity_ = parcIdentity_Acquire(other.identity_); +Identity::Identity(const Identity &other) { + pwd_ = other.pwd_; + filename_ = other.filename_; + signer_ = other.signer_; + cert_ = other.cert_; } -Identity::Identity(Identity &&other) - : identity_(nullptr), signer_(move(other.signer_)) { - parcSecurity_Init(); - identity_ = parcIdentity_Acquire(other.identity_); - parcIdentity_Release(&other.identity_); +Identity::Identity(Identity &&other) { + signer_ = std::move(other.signer_); + other.signer_.reset(); + cert_ = std::move(other.cert_); + other.cert_.reset(); + pwd_ = other.pwd_; + other.pwd_ = ""; + filename_ = other.filename_; + other.filename_ = ""; + signer_ = other.signer_; + other.signer_ = nullptr; } -Identity::~Identity() { - if (identity_) parcIdentity_Release(&identity_); - parcSecurity_Fini(); -} +Identity::~Identity() {} shared_ptr<AsymmetricSigner> Identity::getSigner() const { return signer_; } -string Identity::getFilename() const { - return string(parcIdentity_GetFileName(identity_)); -} +string Identity::getFilename() const { return filename_; } -string Identity::getPassword() const { - return string(parcIdentity_GetPassWord(identity_)); +std::shared_ptr<X509> Identity::getCertificate() const { return cert_; } +std::shared_ptr<EVP_PKEY> Identity::getPrivateKey() const { + return signer_->key_; } +string Identity::getPassword() const { return pwd_; } + Identity Identity::generateIdentity(const string &subject_name) { string keystore_name = "keystore"; string keystore_password = "password"; diff --git a/libtransport/src/auth/signer.cc b/libtransport/src/auth/signer.cc index 99c3d099d..884e850ca 100644 --- a/libtransport/src/auth/signer.cc +++ b/libtransport/src/auth/signer.cc @@ -15,193 +15,214 @@ #include <hicn/transport/auth/signer.h> -extern "C" { -#ifndef _WIN32 -TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat") -#endif -#include <hicn/hicn.h> -} - -#include <chrono> - -#define ALLOW_UNALIGNED_READS 1 - using namespace std; namespace transport { namespace auth { -Signer::Signer() : signer_(nullptr), key_id_(nullptr) { parcSecurity_Init(); } +// --------------------------------------------------------- +// Base Signer +// --------------------------------------------------------- +Signer::Signer() + : suite_(CryptoSuite::UNKNOWN), signature_len_(0), key_(nullptr) {} -Signer::Signer(PARCSigner *signer) : Signer() { setSigner(signer); } - -Signer::~Signer() { - if (signer_) parcSigner_Release(&signer_); - if (key_id_) parcKeyId_Release(&key_id_); - parcSecurity_Fini(); -} +Signer::~Signer() {} void Signer::signPacket(PacketPtr packet) { - parcAssertNotNull(signer_, "Expected non-null signer"); - - const utils::MemBuf &header_chain = *packet; + assert(key_ != nullptr); core::Packet::Format format = packet->getFormat(); - auto suite = getCryptoSuite(); - size_t signature_len = getSignatureSize(); if (!packet->authenticationHeader()) { throw errors::MalformedAHPacketException(); } - packet->setSignatureSize(signature_len); + // Set signature size + size_t signature_field_len = getSignatureFieldSize(); + packet->setSignatureSize(signature_field_len); + packet->setSignatureSizeGap(0u); // 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->resetForHash(); - // Fill in the HICN_AH header + // Fill in the hICN AH header auto now = chrono::duration_cast<chrono::milliseconds>( chrono::system_clock::now().time_since_epoch()) .count(); packet->setSignatureTimestamp(now); - packet->setValidationAlgorithm(suite); + packet->setValidationAlgorithm(suite_); - // Set the key ID - KeyId key_id; - key_id.first = static_cast<uint8_t *>( - parcBuffer_Overlay((PARCBuffer *)parcKeyId_GetKeyId(key_id_), 0)); - packet->setKeyId(key_id); + // Set key ID + vector<uint8_t> key_id = key_id_.getDigest(); + packet->setKeyId({key_id.data(), key_id.size()}); - // Calculate hash - CryptoHasher hasher(parcSigner_GetCryptoHasher(signer_)); - const utils::MemBuf *current = &header_chain; + // Reset fields to compute the packet hash + packet->resetForHash(); - hasher.init(); + // Compute the signature and put it in the packet + signBuffer(packet); + hicn_packet_copy_header(format, &header_copy, packet->packet_start_, false); - do { - hasher.updateBytes(current->data(), current->length()); - current = current->next(); - } while (current != &header_chain); + // Set the gap between the signature field size and the signature real size. + packet->setSignatureSizeGap(signature_field_len - signature_len_); + memcpy(packet->getSignature(), signature_.data(), signature_len_); +} - CryptoHash hash = hasher.finalize(); +void Signer::signBuffer(const std::vector<uint8_t> &buffer) { + assert(key_ != nullptr); + CryptoHashEVP hash_evp = CryptoHash::getEVP(getHashType()); - // Compute signature - PARCSignature *signature = parcSigner_SignDigestNoAlloc( - signer_, hash.hash_, packet->getSignature(), (uint32_t)signature_len); - PARCBuffer *buffer = parcSignature_GetSignature(signature); - size_t bytes_len = parcBuffer_Remaining(buffer); + if (hash_evp == nullptr) { + throw errors::RuntimeException("Unknown hash type"); + } - if (bytes_len > signature_len) { - throw errors::MalformedAHPacketException(); + shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free); + + if (mdctx == nullptr) { + throw errors::RuntimeException("Digest context allocation failed"); } - // Put signature in AH header - hicn_packet_copy_header(format, &header_copy, packet->packet_start_, false); + if (EVP_DigestSignInit(mdctx.get(), nullptr, (*hash_evp)(), nullptr, + key_.get()) != 1) { + throw errors::RuntimeException("Digest initialization failed"); + } - // Release allocated objects - parcSignature_Release(&signature); -} + if (EVP_DigestSignUpdate(mdctx.get(), buffer.data(), buffer.size()) != 1) { + throw errors::RuntimeException("Digest update failed"); + } -void Signer::setSigner(PARCSigner *signer) { - parcAssertNotNull(signer, "Expected non-null signer"); + if (EVP_DigestSignFinal(mdctx.get(), nullptr, &signature_len_) != 1) { + throw errors::RuntimeException("Digest computation failed"); + } - if (signer_) parcSigner_Release(&signer_); - if (key_id_) parcKeyId_Release(&key_id_); + signature_.resize(signature_len_); - signer_ = parcSigner_Acquire(signer); - key_id_ = parcSigner_CreateKeyId(signer_); -} + if (EVP_DigestSignFinal(mdctx.get(), signature_.data(), &signature_len_) != + 1) { + throw errors::RuntimeException("Digest computation failed"); + } -size_t Signer::getSignatureSize() const { - parcAssertNotNull(signer_, "Expected non-null signer"); - return parcSigner_GetSignatureSize(signer_); + signature_.resize(signature_len_); } -CryptoSuite Signer::getCryptoSuite() const { - parcAssertNotNull(signer_, "Expected non-null signer"); - return static_cast<CryptoSuite>(parcSigner_GetCryptoSuite(signer_)); -} +void Signer::signBuffer(const utils::MemBuf *buffer) { + assert(key_ != nullptr); + CryptoHashEVP hash_evp = CryptoHash::getEVP(getHashType()); -CryptoHashType Signer::getCryptoHashType() const { - parcAssertNotNull(signer_, "Expected non-null signer"); - return static_cast<CryptoHashType>(parcSigner_GetCryptoHashType(signer_)); -} + if (hash_evp == nullptr) { + throw errors::RuntimeException("Unknown hash type"); + } -PARCSigner *Signer::getParcSigner() const { return signer_; } + const utils::MemBuf *p = buffer; + shared_ptr<EVP_MD_CTX> mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_free); -PARCKeyStore *Signer::getParcKeyStore() const { - parcAssertNotNull(signer_, "Expected non-null signer"); - return parcSigner_GetKeyStore(signer_); -} + if (mdctx == nullptr) { + throw errors::RuntimeException("Digest context allocation failed"); + } + + 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"); + } -AsymmetricSigner::AsymmetricSigner(CryptoSuite suite, PARCKeyStore *key_store) { - parcAssertNotNull(key_store, "Expected non-null key_store"); + p = p->next(); + } while (p != buffer); - auto crypto_suite = static_cast<PARCCryptoSuite>(suite); + if (EVP_DigestSignFinal(mdctx.get(), nullptr, &signature_len_) != 1) { + throw errors::RuntimeException("Digest computation failed"); + } + + signature_.resize(signature_len_); - switch (suite) { - case CryptoSuite::DSA_SHA256: - case CryptoSuite::RSA_SHA256: - case CryptoSuite::RSA_SHA512: - case CryptoSuite::ECDSA_256K1: - break; - default: - throw errors::RuntimeException( - "Invalid crypto suite for asymmetric signer"); + if (EVP_DigestSignFinal(mdctx.get(), signature_.data(), &signature_len_) != + 1) { + throw errors::RuntimeException("Digest computation failed"); } - setSigner( - parcSigner_Create(parcPublicKeySigner_Create(key_store, crypto_suite), - PARCPublicKeySignerAsSigner)); + signature_.resize(signature_len_); } -SymmetricSigner::SymmetricSigner(CryptoSuite suite, PARCKeyStore *key_store) { - parcAssertNotNull(key_store, "Expected non-null key_store"); +vector<uint8_t> Signer::getSignature() const { return signature_; } - auto crypto_suite = static_cast<PARCCryptoSuite>(suite); +size_t Signer::getSignatureSize() const { return signature_len_; } - switch (suite) { - case CryptoSuite::HMAC_SHA256: - case CryptoSuite::HMAC_SHA512: - break; - default: - throw errors::RuntimeException( - "Invalid crypto suite for symmetric signer"); +size_t Signer::getSignatureFieldSize() const { + if (signature_len_ % 4 == 0) { + return signature_len_; } - setSigner(parcSigner_Create(parcSymmetricKeySigner_Create( - (PARCSymmetricKeyStore *)key_store, - parcCryptoSuite_GetCryptoHash(crypto_suite)), - PARCSymmetricKeySignerAsSigner)); + return (signature_len_ + 4) - (signature_len_ % 4); } -SymmetricSigner::SymmetricSigner(CryptoSuite suite, const string &passphrase) { - auto crypto_suite = static_cast<PARCCryptoSuite>(suite); - - switch (suite) { - case CryptoSuite::HMAC_SHA256: - case CryptoSuite::HMAC_SHA512: - break; - default: - throw errors::RuntimeException( - "Invalid crypto suite for symmetric signer"); - } +CryptoHashType Signer::getHashType() const { + return ::transport::auth::getHashType(suite_); +} + +CryptoSuite Signer::getSuite() const { return suite_; } - PARCBufferComposer *composer = parcBufferComposer_Create(); - parcBufferComposer_PutString(composer, passphrase.c_str()); - PARCBuffer *key_buf = parcBufferComposer_ProduceBuffer(composer); - parcBufferComposer_Release(&composer); +// --------------------------------------------------------- +// Void Signer +// --------------------------------------------------------- +void VoidSigner::signPacket(PacketPtr packet){}; - PARCSymmetricKeyStore *key_store = parcSymmetricKeyStore_Create(key_buf); - PARCSymmetricKeySigner *key_signer = parcSymmetricKeySigner_Create( - key_store, parcCryptoSuite_GetCryptoHash(crypto_suite)); +void VoidSigner::signBuffer(const std::vector<uint8_t> &buffer){}; - setSigner(parcSigner_Create(key_signer, PARCSymmetricKeySignerAsSigner)); +void VoidSigner::signBuffer(const utils::MemBuf *buffer){}; + +// --------------------------------------------------------- +// Asymmetric Signer +// --------------------------------------------------------- +AsymmetricSigner::AsymmetricSigner(CryptoSuite suite, shared_ptr<EVP_PKEY> key, + shared_ptr<EVP_PKEY> pub_key) { + suite_ = suite; + key_ = key; + key_id_ = CryptoHash(getHashType()); + + vector<uint8_t> pbk(i2d_PublicKey(pub_key.get(), nullptr)); + uint8_t *pbk_ptr = pbk.data(); + int len = i2d_PublicKey(pub_key.get(), &pbk_ptr); + + signature_len_ = EVP_PKEY_size(key.get()); + signature_.resize(signature_len_); + key_id_.computeDigest(pbk_ptr, len); +} + +size_t AsymmetricSigner::getSignatureFieldSize() const { + size_t field_size = EVP_PKEY_size(key_.get()); + + if (field_size % 4 == 0) { + return field_size; + } + + return (field_size + 4) - (field_size % 4); +} + +// --------------------------------------------------------- +// Symmetric Signer +// --------------------------------------------------------- +SymmetricSigner::SymmetricSigner(CryptoSuite suite, const string &passphrase) { + suite_ = suite; + 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); + key_id_ = CryptoHash(getHashType()); + + CryptoHashEVP hash_evp = CryptoHash::getEVP(getHashType()); + + if (hash_evp == nullptr) { + throw errors::RuntimeException("Unknown hash type"); + } - parcSymmetricKeySigner_Release(&key_signer); - parcSymmetricKeyStore_Release(&key_store); - parcBuffer_Release(&key_buf); + signature_len_ = EVP_MD_size((*hash_evp)()); + signature_.resize(signature_len_); + key_id_.computeDigest((uint8_t *)passphrase.c_str(), passphrase.size()); } } // namespace auth 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 |