diff options
Diffstat (limited to 'src/lib/sec_profile.cpp')
-rw-r--r-- | src/lib/sec_profile.cpp | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/src/lib/sec_profile.cpp b/src/lib/sec_profile.cpp new file mode 100644 index 0000000..f9d0de8 --- /dev/null +++ b/src/lib/sec_profile.cpp @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2021 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "sec_profile.hpp" +#include "types.h" +#include "defaults.h" +#include <ctime> +#include <algorithm> + +namespace rnp { +bool +SecurityRule::operator==(const SecurityRule &src) const +{ + return (type == src.type) && (feature == src.feature) && (from == src.from) && + (level == src.level) && (override == src.override) && (action == src.action); +} + +bool +SecurityRule::operator!=(const SecurityRule &src) const +{ + return !(*this == src); +} + +bool +SecurityRule::matches(FeatureType ftype, + int fval, + uint64_t ftime, + SecurityAction faction) const noexcept +{ + if ((type != ftype) || (feature != fval) || (from > ftime)) { + return false; + } + return (action == SecurityAction::Any) || (faction == SecurityAction::Any) || + (action == faction); +} + +size_t +SecurityProfile::size() const noexcept +{ + return rules_.size(); +} + +SecurityRule & +SecurityProfile::add_rule(const SecurityRule &rule) +{ + rules_.push_back(rule); + return rules_.back(); +} + +SecurityRule & +SecurityProfile::add_rule(SecurityRule &&rule) +{ + rules_.emplace_back(rule); + return rules_.back(); +} + +bool +SecurityProfile::del_rule(const SecurityRule &rule) +{ + size_t old_size = rules_.size(); + rules_.erase(std::remove_if(rules_.begin(), + rules_.end(), + [rule](const SecurityRule &item) { return item == rule; }), + rules_.end()); + return old_size != rules_.size(); +} + +void +SecurityProfile::clear_rules(FeatureType type, int feature) +{ + rules_.erase(std::remove_if(rules_.begin(), + rules_.end(), + [type, feature](const SecurityRule &item) { + return (item.type == type) && (item.feature == feature); + }), + rules_.end()); +} + +void +SecurityProfile::clear_rules(FeatureType type) +{ + rules_.erase( + std::remove_if(rules_.begin(), + rules_.end(), + [type](const SecurityRule &item) { return item.type == type; }), + rules_.end()); +} + +void +SecurityProfile::clear_rules() +{ + rules_.clear(); +} + +bool +SecurityProfile::has_rule(FeatureType type, + int value, + uint64_t time, + SecurityAction action) const noexcept +{ + for (auto &rule : rules_) { + if (rule.matches(type, value, time, action)) { + return true; + } + } + return false; +} + +const SecurityRule & +SecurityProfile::get_rule(FeatureType type, + int value, + uint64_t time, + SecurityAction action) const +{ + const SecurityRule *res = nullptr; + for (auto &rule : rules_) { + if (!rule.matches(type, value, time, action)) { + continue; + } + if (rule.override) { + return rule; + } + if (!res || (res->from < rule.from)) { + res = &rule; + } + } + if (!res) { + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + return *res; +} + +SecurityLevel +SecurityProfile::hash_level(pgp_hash_alg_t hash, + uint64_t time, + SecurityAction action) const noexcept +{ + if (!has_rule(FeatureType::Hash, hash, time, action)) { + return def_level(); + } + + try { + return get_rule(FeatureType::Hash, hash, time, action).level; + } catch (const std::exception &e) { + /* this should never happen however we need to satisfy noexcept specifier */ + return def_level(); + } +} + +SecurityLevel +SecurityProfile::def_level() const +{ + return SecurityLevel::Default; +}; + +SecurityContext::SecurityContext() : time_(0), prov_state_(NULL), rng(RNG::Type::DRBG) +{ + /* Initialize crypto provider if needed (currently only for OpenSSL 3.0) */ + if (!rnp::backend_init(&prov_state_)) { + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + /* Mark SHA-1 data signature insecure since 2019-01-19, as GnuPG does */ + profile.add_rule({FeatureType::Hash, + PGP_HASH_SHA1, + SecurityLevel::Insecure, + 1547856000, + SecurityAction::VerifyData}); + /* Mark SHA-1 key signature insecure since 2024-01-19 by default */ + profile.add_rule({FeatureType::Hash, + PGP_HASH_SHA1, + SecurityLevel::Insecure, + 1705629600, + SecurityAction::VerifyKey}); + /* Mark MD5 insecure since 2012-01-01 */ + profile.add_rule({FeatureType::Hash, PGP_HASH_MD5, SecurityLevel::Insecure, 1325376000}); +} + +SecurityContext::~SecurityContext() +{ + rnp::backend_finish(prov_state_); +} + +size_t +SecurityContext::s2k_iterations(pgp_hash_alg_t halg) +{ + if (!s2k_iterations_.count(halg)) { + s2k_iterations_[halg] = + pgp_s2k_compute_iters(halg, DEFAULT_S2K_MSEC, DEFAULT_S2K_TUNE_MSEC); + } + return s2k_iterations_[halg]; +} + +void +SecurityContext::set_time(uint64_t time) noexcept +{ + time_ = time; +} + +uint64_t +SecurityContext::time() const noexcept +{ + return time_ ? time_ : ::time(NULL); +} + +} // namespace rnp |