Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cdoc/CDoc2Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ createRSACapsule(flatbuffers::FlatBufferBuilder& builder, const libcdoc::Recipie
return cdoc20::header::CreateRecipientRecord(builder,
cdoc20::header::Capsule::recipients_RSAPublicKeyCapsule,
capsule.Union(),
builder.CreateString(rcpt.getLabel({})),
builder.CreateString(rcpt.getLabel({{"x-expiry-time", rcpt.expiry_ts == 0 ? std::string() : std::to_string(rcpt.expiry_ts)}})),
builder.CreateVector(xor_key),
cdoc20::header::FMKEncryptionMethod::XOR);
}
Expand Down Expand Up @@ -138,7 +138,7 @@ createECCCapsule(flatbuffers::FlatBufferBuilder& builder, const libcdoc::Recipie
return cdoc20::header::CreateRecipientRecord(builder,
cdoc20::header::Capsule::recipients_ECCPublicKeyCapsule,
capsule.Union(),
builder.CreateString(rcpt.getLabel({})),
builder.CreateString(rcpt.getLabel({{"x-expiry-time", rcpt.expiry_ts == 0 ? std::string() : std::to_string(rcpt.expiry_ts)}})),
builder.CreateVector(xor_key),
cdoc20::header::FMKEncryptionMethod::XOR);
}
Expand Down
21 changes: 18 additions & 3 deletions cdoc/Certificate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,21 @@ Certificate::getSerialNumber() const
return getName(cert, NID_serialNumber);
}

time_t
Certificate::getNotAfter() const
{
if(!cert)
return 0;
tm tm{};
if(ASN1_TIME_to_tm(X509_get0_notAfter(cert.get()), &tm) != 1)
return 0;
#ifdef _WIN32
return _mkgmtime(&tm);
#else
return timegm(&tm);
#endif
}



std::vector<std::string>
Expand All @@ -85,8 +100,8 @@ Certificate::policies() const
if(!cert)
return list;

auto p = static_cast<CERTIFICATEPOLICIES *>(X509_get_ext_d2i(cert.get(), NID_certificate_policies, nullptr, nullptr));
auto cp = std::unique_ptr<CERTIFICATEPOLICIES,decltype(&CERTIFICATEPOLICIES_free)>(p,CERTIFICATEPOLICIES_free);
auto cp = make_unique_cast<CERTIFICATEPOLICIES_free>(X509_get_ext_d2i(
cert.get(), NID_certificate_policies, nullptr, nullptr));
if(!cp)
return list;

Expand Down Expand Up @@ -122,7 +137,7 @@ Certificate::getAlgorithm() const
return (alg == EVP_PKEY_RSA) ? Algorithm::RSA : Algorithm::ECC;
}

std::vector<uint8_t> Certificate::getDigest()
std::vector<uint8_t> Certificate::getDigest() const
{
if(!cert)
return {};
Expand Down
3 changes: 2 additions & 1 deletion cdoc/Certificate.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ class Certificate {

std::vector<uint8_t> getPublicKey() const;
Algorithm getAlgorithm() const;
time_t getNotAfter() const;

std::vector<uint8_t> getDigest();
std::vector<uint8_t> getDigest() const;
};

} // Namespace
Expand Down
2 changes: 1 addition & 1 deletion cdoc/Io.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

namespace libcdoc {

class DataSource;
struct DataSource;

/**
* @brief The DataConsumer class
Expand Down
143 changes: 59 additions & 84 deletions cdoc/Recipient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,20 @@ static constexpr std::string_view eid_strs[] = {
};

Recipient
Recipient::makeSymmetric(const std::string& label, int32_t kdf_iter)
Recipient::makeSymmetric(std::string label, int32_t kdf_iter)
{
Recipient rcpt(Type::SYMMETRIC_KEY);
rcpt.label = label;
rcpt.label = std::move(label);
rcpt.kdf_iter = kdf_iter;
return rcpt;
}

Recipient
Recipient::makePublicKey(const std::string& label, const std::vector<uint8_t>& public_key, PKType pk_type)
Recipient::makePublicKey(std::string label, const std::vector<uint8_t>& public_key, PKType pk_type)
{
if (public_key.empty()) return Recipient(Type::NONE);
Recipient rcpt(Type::PUBLIC_KEY);
rcpt.label = label;
rcpt.label = std::move(label);
rcpt.pk_type = pk_type;
if (pk_type == PKType::ECC && public_key[0] == 0x30) {
// 0x30 identifies SEQUENCE tag in ASN.1 encoding
Expand All @@ -77,13 +77,14 @@ Recipient::makePublicKey(const std::string& label, const std::vector<uint8_t>& p
Recipient
Recipient::makeCertificate(std::string label, std::vector<uint8_t> cert)
{
Recipient rcpt(Type::PUBLIC_KEY);
rcpt.label = std::move(label);
Recipient rcpt(Type::PUBLIC_KEY);
rcpt.label = std::move(label);
rcpt.cert = std::move(cert);
Certificate ssl(rcpt.cert);
rcpt.rcpt_key = ssl.getPublicKey();
rcpt.pk_type = (ssl.getAlgorithm() == libcdoc::Certificate::RSA) ? PKType::RSA : PKType::ECC;
return rcpt;
Certificate x509(rcpt.cert);
rcpt.rcpt_key = x509.getPublicKey();
rcpt.pk_type = (x509.getAlgorithm() == libcdoc::Certificate::RSA) ? PKType::RSA : PKType::ECC;
rcpt.expiry_ts = x509.getNotAfter();
return rcpt;
}

Recipient
Expand Down Expand Up @@ -138,26 +139,10 @@ Recipient::isTheSameRecipient(const std::vector<uint8_t>& public_key) const
return rcpt_key == public_key;
}

static std::string
buildLabel(std::vector<std::pair<std::string_view, std::string_view>> components)
{
std::ostringstream ofs;
ofs << LABELPREFIX;
bool first = true;
for (auto& [key, value] : components) {
if (!value.empty()) {
if (!first) ofs << '&';
ofs << libcdoc::urlEncode(key) << '=' << libcdoc::urlEncode(value);
first = false;
}
}
return ofs.str();
}

static Recipient::EIDType
getEIDType(const std::vector<std::string>& policies)
{
for (std::vector<std::string>::const_reference policy : policies)
for (const auto& policy : policies)
{
if (policy.starts_with("1.3.6.1.4.1.51361.1.1.3") ||
policy.starts_with("1.3.6.1.4.1.51361.1.2.3")) {
Expand All @@ -181,113 +166,103 @@ getEIDType(const std::vector<std::string>& policies)
return Recipient::EIDType::Unknown;
}

static std::string
BuildLabelEID(const std::vector<uint8_t>& cert)
static void
buildLabel(std::ostream& ofs, std::string_view type, const std::initializer_list<std::pair<std::string_view, std::string_view>> &components)
{
Certificate x509(cert);
Recipient::EIDType type = getEIDType(x509.policies());
std::string cn = x509.getCommonName();
std::string sn = x509.getSerialNumber();
std::string gn = x509.getGivenName();
if (!gn.empty()) {
return buildLabel({
{"v", std::to_string(CDoc2::KEYLABELVERSION)},
{"type", eid_strs[type]},
{"cn", cn},
{"serial_number", sn}
});
} else {
return buildLabel({
{"v", std::to_string(CDoc2::KEYLABELVERSION)},
{"type", eid_strs[type]},
{"cn", cn},
{"serial_number", sn},
{"last_name", x509.getSurname()},
{"first_name", gn}
});
ofs << LABELPREFIX;
ofs << "v" << '=' << std::to_string(CDoc2::KEYLABELVERSION) << '&'
<< "type" << '=' << type;
for (auto& [key, value] : components) {
if (value.empty())
continue;
ofs << '&';
ofs << urlEncode(key) << '=' << urlEncode(value);
}
}

static std::string
BuildLabelCertificate(std::string_view file, const std::vector<uint8_t>& cert)
static void
BuildLabelEID(std::ostream& ofs, Recipient::EIDType type, const Certificate& x509)
{
Certificate x509(cert);
return buildLabel({
{"v", std::to_string(CDoc2::KEYLABELVERSION)},
{"type", "cert"},
buildLabel(ofs, eid_strs[type], {
{"cn", x509.getCommonName()},
{"serial_number", x509.getSerialNumber()},
{"last_name", x509.getSurname()},
{"first_name", x509.getGivenName()},
});
}

static void
BuildLabelCertificate(std::ostream &ofs, std::string_view file, const Certificate& x509)
{
buildLabel(ofs, "cert", {
{"file", file},
{"cn", x509.getCommonName()},
{"cert_sha1", toHex(x509.getDigest())}
});
}

static std::string
BuildLabelPublicKey(int version, const std::string file)
static void
BuildLabelPublicKey(std::ostream &ofs, const std::string file)
{
return buildLabel({
{"v", std::to_string(version)},
{"type", "pub_key"},
buildLabel(ofs, "pub_key", {
{"file", file}
});
}

static std::string
BuildLabelSymmetricKey(int version, const std::string& label, const std::string file)
static void
BuildLabelSymmetricKey(std::ostream &ofs, const std::string& label, const std::string file)
{
return buildLabel({
{"v", std::to_string(version)},
{"type", "secret"},
buildLabel(ofs, "secret", {
{"label", label},
{"file", file}
});
}

static std::string
BuildLabelPassword(int version, const std::string& label)
static void
BuildLabelPassword(std::ostream &ofs, const std::string& label)
{
return buildLabel({
{"v", std::to_string(version)},
{"type", "pw"},
buildLabel(ofs, "pw", {
{"label", label}
});
}

std::string
Recipient::getLabel(std::vector<std::pair<std::string_view, std::string_view>> extra) const
Recipient::getLabel(const std::vector<std::pair<std::string_view, std::string_view>> &extra) const
{
LOG_DBG("Generating label");
if (!label.empty()) return label;
std::ostringstream ofs;
switch(type) {
case NONE:
case NONE:
LOG_DBG("The recipient is not initialized");
break;
case SYMMETRIC_KEY:
if (kdf_iter > 0) {
ofs << BuildLabelPassword(CDoc2::KEYLABELVERSION, key_name);
BuildLabelPassword(ofs, key_name);
} else {
ofs << BuildLabelSymmetricKey(CDoc2::KEYLABELVERSION, key_name, file_name);
BuildLabelSymmetricKey(ofs, key_name, file_name);
}
break;
case PUBLIC_KEY:
if (!cert.empty()) {
Certificate x509(cert);
EIDType eid_type = getEIDType(x509.policies());
if (eid_type != EIDType::Unknown) {
ofs << BuildLabelEID(cert);
if (auto type = getEIDType(x509.policies()); type != EIDType::Unknown) {
BuildLabelEID(ofs, type, x509);
} else {
ofs << BuildLabelCertificate(file_name, cert);
BuildLabelCertificate(ofs, file_name, x509);
}
} else {
ofs << BuildLabelPublicKey(CDoc2::KEYLABELVERSION, file_name);
BuildLabelPublicKey(ofs, file_name);
}
break;
case KEYSHARE:
break;
}
for (auto& [key, value] : extra) {
if (!value.empty()) {
ofs << '&';
ofs << libcdoc::urlEncode(key) << '=' << libcdoc::urlEncode(value);
}
if (value.empty())
continue;
ofs << '&';
ofs << urlEncode(key) << '=' << urlEncode(value);
}
LOG_DBG("Generated label: {}", ofs.str());
return ofs.str();
Expand Down
20 changes: 3 additions & 17 deletions cdoc/Recipient.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,20 +80,6 @@ struct CDOC_EXPORT Recipient {
DigiID_EResident
};

/**
* @brief Extra parameters for automatic label generation
*/
enum Params : unsigned char {
/**
* @brief Name of symmetric key/password ('label')
*/
LABEL,
/**
* @brief Public key or certificate filename ('file')
*/
FILE
};

Recipient() = default;

/**
Expand Down Expand Up @@ -199,15 +185,15 @@ struct CDOC_EXPORT Recipient {
* @param kdf_iter the number of PBKDF iterations (0 if full key is provided)
* @return a new Recipient structure
*/
static Recipient makeSymmetric(const std::string& label, int32_t kdf_iter);
static Recipient makeSymmetric(std::string label, int32_t kdf_iter);
/**
* @brief Create a new public key based Recipient
* @param label the label text
* @param public_key the public key value
* @param pk_type the algorithm type (either ECC or RSA)
* @return a new Recipient structure
*/
static Recipient makePublicKey(const std::string& label, const std::vector<uint8_t>& public_key, PKType pk_type);
static Recipient makePublicKey(std::string label, const std::vector<uint8_t>& public_key, PKType pk_type);
/**
* @brief Create a new certificate based Recipient
* @param label the label text
Expand Down Expand Up @@ -257,7 +243,7 @@ struct CDOC_EXPORT Recipient {
* @param extra additional parameter values to use
* @return a label value
*/
std::string getLabel(std::vector<std::pair<std::string_view, std::string_view>> extra) const;
std::string getLabel(const std::vector<std::pair<std::string_view, std::string_view>> &extra) const;

/**
* @brief parse machine-readable CDoc2 label
Expand Down
9 changes: 4 additions & 5 deletions cdoc/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,13 @@ buildURL(const std::string& host, int port)
return std::string("https://") + host + ":" + std::to_string(port) + "/";
}

std::string
urlEncode(std::string_view src)
std::ostream&
operator<<(std::ostream& escaped, urlEncode src)
{
std::ostringstream escaped;
escaped.fill('0');
escaped << std::hex;

for (auto c : src) {
for (auto c : src.src) {
// Keep alphanumeric and other accepted characters intact
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
escaped << c;
Expand All @@ -136,7 +135,7 @@ urlEncode(std::string_view src)
escaped << '%' << std::setw(2) << int((unsigned char) c);
escaped << std::nouppercase;
}
return escaped.str();
return escaped;
}

std::string
Expand Down
Loading
Loading