Source code

Revision control

Copy as Markdown

Other Tools

/*
* 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